Timber - Version 0.20.7

Version Description

  • Cleaned-up logic for {{post.next}} and {{post.prev}} (thanks @alexlrobertson)
  • Simplifiying internals of TimberCore, TimberPost (thanks @alexlrobertson)
  • Initialization of variables from stolen WP functions (thanks @alexlrobertson)
  • Fixed Twitter API call (thanks @asecondwill)
  • Matched TimberMenu fallback behavior to grab pages_men (@jaredNova)
  • Fixed a bug with the_title filter (thanks @kuus)
  • Fixed weird conflicts when ACF names match methods (@jaredNova)
  • Added a filter for timber_output (thanks @aristath)
  • Fix for galleries showing only 5 images (thanks @IJMacD)
Download this release

Release Info

Developer jarednova
Plugin Icon 128x128 Timber
Version 0.20.7
Comparing to
See all releases

Code changes from version 0.20.6 to 0.20.7

Files changed (406) hide show
  1. functions/integrations/wpcli-timber.php +1 -1
  2. functions/timber-archives.php +2 -0
  3. functions/timber-comment.php +2 -1
  4. functions/timber-core-interface.php +3 -0
  5. functions/timber-core.php +16 -13
  6. functions/timber-helper.php +15 -6
  7. functions/timber-image-helper.php +14 -1
  8. functions/timber-image.php +32 -21
  9. functions/timber-loader.php +8 -5
  10. functions/timber-menu-item.php +6 -0
  11. functions/timber-menu.php +22 -1
  12. functions/timber-post-getter.php +2 -2
  13. functions/timber-post.php +29 -25
  14. functions/timber-routes.php +4 -0
  15. functions/timber-site.php +1 -0
  16. functions/timber-term-getter.php +3 -3
  17. functions/timber-term.php +2 -2
  18. readme.txt +13 -2
  19. timber-starter-theme/timber-starter-theme/404.php +13 -0
  20. timber-starter-theme/timber-starter-theme/archive.php +40 -0
  21. timber-starter-theme/timber-starter-theme/author.php +20 -0
  22. timber-starter-theme/timber-starter-theme/footer.php +13 -0
  23. timber-starter-theme/timber-starter-theme/functions.php +54 -0
  24. timber-starter-theme/timber-starter-theme/header.php +7 -0
  25. timber-starter-theme/timber-starter-theme/index.php +29 -0
  26. timber-starter-theme/timber-starter-theme/js/site.js +5 -0
  27. timber-starter-theme/timber-starter-theme/page.php +27 -0
  28. timber-starter-theme/timber-starter-theme/screenshot.png +0 -0
  29. timber-starter-theme/timber-starter-theme/search.php +19 -0
  30. timber-starter-theme/timber-starter-theme/sidebar.php +10 -0
  31. timber-starter-theme/timber-starter-theme/single.php +24 -0
  32. timber-starter-theme/timber-starter-theme/style.css +4 -0
  33. timber-starter-theme/timber-starter-theme/views/404.twig +5 -0
  34. timber-starter-theme/timber-starter-theme/views/author.twig +8 -0
  35. timber-starter-theme/timber-starter-theme/views/base.twig +51 -0
  36. timber-starter-theme/timber-starter-theme/views/comment.twig +4 -0
  37. timber-starter-theme/timber-starter-theme/views/footer.twig +1 -0
  38. timber-starter-theme/timber-starter-theme/views/html-header.twig +15 -0
  39. timber-starter-theme/timber-starter-theme/views/index.twig +10 -0
  40. timber-starter-theme/timber-starter-theme/views/page-plugin.twig +7 -0
  41. timber-starter-theme/timber-starter-theme/views/page.twig +18 -0
  42. timber-starter-theme/timber-starter-theme/views/sidebar.twig +1 -0
  43. timber-starter-theme/timber-starter-theme/views/single-password.twig +8 -0
  44. timber-starter-theme/timber-starter-theme/views/single.twig +35 -0
  45. timber-starter-theme/timber-starter-theme/views/tease-post.twig +9 -0
  46. timber-starter-theme/timber-starter-theme/views/tease.twig +10 -0
  47. timber-starter-theme/views/single.twig +7 -8
  48. timber.php +9 -6
  49. vendor/autoload.php +1 -1
  50. vendor/composer/autoload_real.php +4 -4
  51. vendor/vendor/asm89/twig-cache-extension/.gitignore +4 -0
  52. vendor/vendor/asm89/twig-cache-extension/.travis.yml +14 -0
  53. vendor/vendor/asm89/twig-cache-extension/LICENSE +19 -0
  54. vendor/vendor/asm89/twig-cache-extension/README.md +195 -0
  55. vendor/vendor/asm89/twig-cache-extension/composer.json +29 -0
  56. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheProvider/DoctrineCacheAdapter.php +49 -0
  57. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheProviderInterface.php +34 -0
  58. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/GenerationalCacheStrategy.php +79 -0
  59. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/IndexedChainingCacheStrategy.php +75 -0
  60. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/KeyGeneratorInterface.php +29 -0
  61. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/LifetimeCacheStrategy.php +68 -0
  62. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategyInterface.php +47 -0
  63. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/Extension.php +56 -0
  64. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/Node/CacheNode.php +63 -0
  65. vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/TokenParser/Cache.php +56 -0
  66. vendor/vendor/asm89/twig-cache-extension/phpunit.xml.dist +25 -0
  67. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheProvider/DoctrineCacheAdapterTest.php +46 -0
  68. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheStrategy/GenerationCacheStrategyTest.php +80 -0
  69. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheStrategy/IndexedChainingCacheStrategyTest.php +72 -0
  70. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheStrategy/LifetimeCacheStrategyTest.php +68 -0
  71. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/FunctionalExtensionTest.php +185 -0
  72. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/annotation_not_string.twig +2 -0
  73. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/gcs_value.twig +1 -0
  74. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/gcs_value_v2.twig +1 -0
  75. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/ics_no_key.twig +1 -0
  76. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/ics_value.twig +1 -0
  77. vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/lcs_value.twig +1 -0
  78. vendor/vendor/asm89/twig-cache-extension/test/bootstrap.php +16 -0
  79. vendor/vendor/autoload.php +7 -0
  80. vendor/vendor/composer/ClassLoader.php +378 -0
  81. vendor/vendor/composer/autoload_classmap.php +9 -0
  82. vendor/vendor/composer/autoload_namespaces.php +14 -0
  83. vendor/vendor/composer/autoload_psr4.php +9 -0
  84. vendor/vendor/composer/autoload_real.php +53 -0
  85. vendor/vendor/composer/installed.json +311 -0
  86. vendor/vendor/composer/installers/.editorconfig +10 -0
  87. vendor/vendor/composer/installers/.gitignore +3 -0
  88. vendor/vendor/composer/installers/.travis.yml +11 -0
  89. vendor/vendor/composer/installers/LICENSE +19 -0
  90. vendor/vendor/composer/installers/README.md +180 -0
  91. vendor/vendor/composer/installers/composer.json +70 -0
  92. vendor/vendor/composer/installers/phpunit.xml.dist +25 -0
  93. vendor/vendor/composer/installers/src/Composer/Installers/AglInstaller.php +21 -0
  94. vendor/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php +11 -0
  95. vendor/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php +131 -0
  96. vendor/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php +10 -0
  97. vendor/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php +58 -0
  98. vendor/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php +11 -0
  99. vendor/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php +12 -0
  100. vendor/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php +9 -0
  101. vendor/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php +21 -0
  102. vendor/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php +16 -0
  103. vendor/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php +13 -0
  104. vendor/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php +9 -0
  105. vendor/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php +11 -0
  106. vendor/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php +21 -0
  107. vendor/vendor/composer/installers/src/Composer/Installers/Installer.php +149 -0
  108. vendor/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php +15 -0
  109. vendor/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php +9 -0
  110. vendor/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php +9 -0
  111. vendor/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php +9 -0
  112. vendor/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php +10 -0
  113. vendor/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php +9 -0
  114. vendor/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php +16 -0
  115. vendor/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php +11 -0
  116. vendor/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php +9 -0
  117. vendor/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php +50 -0
  118. vendor/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php +111 -0
  119. vendor/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php +47 -0
  120. vendor/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php +10 -0
  121. vendor/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php +11 -0
  122. vendor/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php +9 -0
  123. vendor/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php +11 -0
  124. vendor/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php +21 -0
  125. vendor/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php +32 -0
  126. vendor/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php +22 -0
  127. vendor/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php +58 -0
  128. vendor/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php +36 -0
  129. vendor/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php +26 -0
  130. vendor/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php +14 -0
  131. vendor/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php +38 -0
  132. vendor/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php +14 -0
  133. vendor/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php +9 -0
  134. vendor/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php +11 -0
  135. vendor/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php +11 -0
  136. vendor/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php +10 -0
  137. vendor/vendor/composer/installers/src/bootstrap.php +13 -0
  138. vendor/vendor/composer/installers/tests/Composer/Installers/Test/CakePHPInstallerTest.php +113 -0
  139. vendor/vendor/composer/installers/tests/Composer/Installers/Test/InstallerTest.php +381 -0
  140. vendor/vendor/composer/installers/tests/Composer/Installers/Test/MediaWikiInstallerTest.php +66 -0
  141. vendor/vendor/composer/installers/tests/Composer/Installers/Test/PimcoreInstallerTest.php +44 -0
  142. vendor/vendor/composer/installers/tests/Composer/Installers/Test/PiwikInstallerTest.php +63 -0
  143. vendor/vendor/composer/installers/tests/Composer/Installers/Test/TestCase.php +64 -0
  144. vendor/vendor/composer/installers/tests/bootstrap.php +4 -0
  145. vendor/vendor/dannyvankooten/php-router/.gitignore +36 -0
  146. vendor/vendor/dannyvankooten/php-router/.htaccess +3 -0
  147. vendor/vendor/dannyvankooten/php-router/LICENSE +7 -0
  148. vendor/vendor/dannyvankooten/php-router/README.md +43 -0
  149. vendor/vendor/dannyvankooten/php-router/composer.json +26 -0
  150. vendor/vendor/dannyvankooten/php-router/example.php +37 -0
  151. vendor/vendor/dannyvankooten/php-router/src/PHPRouter/Route.php +115 -0
  152. vendor/vendor/dannyvankooten/php-router/src/PHPRouter/Router.php +164 -0
  153. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/.gitignore +3 -0
  154. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/CHANGELOG.md +8 -0
  155. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Dumper.php +73 -0
  156. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Escaper.php +89 -0
  157. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/DumpException.php +23 -0
  158. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/ExceptionInterface.php +23 -0
  159. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/ParseException.php +148 -0
  160. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/RuntimeException.php +23 -0
  161. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Inline.php +487 -0
  162. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/LICENSE +19 -0
  163. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Parser.php +655 -0
  164. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/README.md +19 -0
  165. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/DumperTest.php +207 -0
  166. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsAnchorAlias.yml +31 -0
  167. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsBasicTests.yml +178 -0
  168. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsBlockMapping.yml +51 -0
  169. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsDocumentSeparator.yml +85 -0
  170. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsErrorTests.yml +25 -0
  171. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsFlowCollections.yml +60 -0
  172. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsFoldedScalars.yml +176 -0
  173. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsNullsAndEmpties.yml +45 -0
  174. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml +1695 -0
  175. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsTypeTransfers.yml +244 -0
  176. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/embededPhp.yml +1 -0
  177. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/escapedCharacters.yml +147 -0
  178. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/index.yml +18 -0
  179. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfComments.yml +65 -0
  180. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfCompact.yml +159 -0
  181. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml +27 -0
  182. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfObjects.yml +11 -0
  183. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfQuotes.yml +33 -0
  184. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml +135 -0
  185. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/unindentedCollections.yml +62 -0
  186. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/InlineTest.php +231 -0
  187. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/ParseExceptionTest.php +30 -0
  188. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/ParserTest.php +660 -0
  189. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/YamlTest.php +31 -0
  190. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Unescaper.php +141 -0
  191. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Yaml.php +100 -0
  192. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/composer.json +31 -0
  193. vendor/vendor/symfony/yaml/Symfony/Component/Yaml/phpunit.xml.dist +29 -0
  194. vendor/vendor/twig/twig/.editorconfig +18 -0
  195. vendor/vendor/twig/twig/.gitignore +2 -0
  196. vendor/vendor/twig/twig/.travis.yml +21 -0
  197. vendor/vendor/twig/twig/CHANGELOG +677 -0
  198. vendor/vendor/twig/twig/LICENSE +31 -0
  199. vendor/vendor/twig/twig/README.rst +15 -0
  200. vendor/vendor/twig/twig/composer.json +42 -0
  201. vendor/vendor/twig/twig/doc/advanced.rst +834 -0
  202. vendor/vendor/twig/twig/doc/advanced_legacy.rst +887 -0
  203. vendor/vendor/twig/twig/doc/api.rst +529 -0
  204. vendor/vendor/twig/twig/doc/coding_standards.rst +101 -0
  205. vendor/vendor/twig/twig/doc/deprecated.rst +103 -0
  206. vendor/vendor/twig/twig/doc/filters/abs.rst +18 -0
  207. vendor/vendor/twig/twig/doc/filters/batch.rst +45 -0
  208. vendor/vendor/twig/twig/doc/filters/capitalize.rst +11 -0
  209. vendor/vendor/twig/twig/doc/filters/convert_encoding.rst +28 -0
  210. vendor/vendor/twig/twig/doc/filters/date.rst +94 -0
  211. vendor/vendor/twig/twig/doc/filters/date_modify.rst +23 -0
  212. vendor/vendor/twig/twig/doc/filters/default.rst +33 -0
  213. vendor/vendor/twig/twig/doc/filters/escape.rst +116 -0
  214. vendor/vendor/twig/twig/doc/filters/first.rst +25 -0
  215. vendor/vendor/twig/twig/doc/filters/format.rst +16 -0
  216. vendor/vendor/twig/twig/doc/filters/index.rst +37 -0
  217. vendor/vendor/twig/twig/doc/filters/join.rst +23 -0
  218. vendor/vendor/twig/twig/doc/filters/json_encode.rst +21 -0
  219. vendor/vendor/twig/twig/doc/filters/keys.rst +11 -0
  220. vendor/vendor/twig/twig/doc/filters/last.rst +25 -0
  221. vendor/vendor/twig/twig/doc/filters/length.rst +11 -0
  222. vendor/vendor/twig/twig/doc/filters/lower.rst +10 -0
  223. vendor/vendor/twig/twig/doc/filters/merge.rst +41 -0
  224. vendor/vendor/twig/twig/doc/filters/nl2br.rst +22 -0
  225. vendor/vendor/twig/twig/doc/filters/number_format.rst +45 -0
  226. vendor/vendor/twig/twig/doc/filters/raw.rst +12 -0
  227. vendor/vendor/twig/twig/doc/filters/replace.rst +19 -0
  228. vendor/vendor/twig/twig/doc/filters/reverse.rst +47 -0
  229. vendor/vendor/twig/twig/doc/filters/round.rst +37 -0
  230. vendor/vendor/twig/twig/doc/filters/slice.rst +70 -0
  231. vendor/vendor/twig/twig/doc/filters/sort.rst +17 -0
  232. vendor/vendor/twig/twig/doc/filters/split.rst +53 -0
  233. vendor/vendor/twig/twig/doc/filters/striptags.rst +15 -0
  234. vendor/vendor/twig/twig/doc/filters/title.rst +11 -0
  235. vendor/vendor/twig/twig/doc/filters/trim.rst +29 -0
  236. vendor/vendor/twig/twig/doc/filters/upper.rst +10 -0
  237. vendor/vendor/twig/twig/doc/filters/url_encode.rst +28 -0
  238. vendor/vendor/twig/twig/doc/functions/attribute.rst +26 -0
  239. vendor/vendor/twig/twig/doc/functions/block.rst +15 -0
  240. vendor/vendor/twig/twig/doc/functions/constant.rst +18 -0
  241. vendor/vendor/twig/twig/doc/functions/cycle.rst +28 -0
  242. vendor/vendor/twig/twig/doc/functions/date.rst +52 -0
  243. vendor/vendor/twig/twig/doc/functions/dump.rst +69 -0
  244. vendor/vendor/twig/twig/doc/functions/include.rst +80 -0
  245. vendor/vendor/twig/twig/doc/functions/index.rst +20 -0
  246. vendor/vendor/twig/twig/doc/functions/max.rst +19 -0
  247. vendor/vendor/twig/twig/doc/functions/min.rst +19 -0
  248. vendor/vendor/twig/twig/doc/functions/parent.rst +20 -0
  249. vendor/vendor/twig/twig/doc/functions/random.rst +29 -0
  250. vendor/vendor/twig/twig/doc/functions/range.rst +45 -0
  251. vendor/vendor/twig/twig/doc/functions/source.rst +21 -0
  252. vendor/vendor/twig/twig/doc/functions/template_from_string.rst +32 -0
  253. vendor/vendor/twig/twig/doc/index.rst +19 -0
  254. vendor/vendor/twig/twig/doc/installation.rst +118 -0
  255. vendor/vendor/twig/twig/doc/internals.rst +138 -0
  256. vendor/vendor/twig/twig/doc/intro.rst +79 -0
  257. vendor/vendor/twig/twig/doc/recipes.rst +475 -0
  258. vendor/vendor/twig/twig/doc/tags/autoescape.rst +71 -0
  259. vendor/vendor/twig/twig/doc/tags/block.rst +11 -0
  260. vendor/vendor/twig/twig/doc/tags/do.rst +12 -0
  261. vendor/vendor/twig/twig/doc/tags/embed.rst +178 -0
  262. vendor/vendor/twig/twig/doc/tags/extends.rst +268 -0
  263. vendor/vendor/twig/twig/doc/tags/filter.rst +21 -0
  264. vendor/vendor/twig/twig/doc/tags/flush.rst +17 -0
  265. vendor/vendor/twig/twig/doc/tags/for.rst +172 -0
  266. vendor/vendor/twig/twig/doc/tags/from.rst +8 -0
  267. vendor/vendor/twig/twig/doc/tags/if.rst +43 -0
  268. vendor/vendor/twig/twig/doc/tags/import.rst +57 -0
  269. vendor/vendor/twig/twig/doc/tags/include.rst +86 -0
  270. vendor/vendor/twig/twig/doc/tags/index.rst +24 -0
  271. vendor/vendor/twig/twig/doc/tags/macro.rst +83 -0
  272. vendor/vendor/twig/twig/doc/tags/sandbox.rst +30 -0
  273. vendor/vendor/twig/twig/doc/tags/set.rst +78 -0
  274. vendor/vendor/twig/twig/doc/tags/spaceless.rst +37 -0
  275. vendor/vendor/twig/twig/doc/tags/use.rst +123 -0
  276. vendor/vendor/twig/twig/doc/tags/verbatim.rst +24 -0
  277. vendor/vendor/twig/twig/doc/templates.rst +873 -0
  278. vendor/vendor/twig/twig/doc/tests/constant.rst +22 -0
  279. vendor/vendor/twig/twig/doc/tests/defined.rst +30 -0
  280. vendor/vendor/twig/twig/doc/tests/divisibleby.rst +14 -0
  281. vendor/vendor/twig/twig/doc/tests/empty.rst +11 -0
  282. vendor/vendor/twig/twig/doc/tests/even.rst +10 -0
  283. vendor/vendor/twig/twig/doc/tests/index.rst +15 -0
  284. vendor/vendor/twig/twig/doc/tests/iterable.rst +19 -0
  285. vendor/vendor/twig/twig/doc/tests/null.rst +12 -0
  286. vendor/vendor/twig/twig/doc/tests/odd.rst +10 -0
  287. vendor/vendor/twig/twig/doc/tests/sameas.rst +14 -0
  288. vendor/vendor/twig/twig/ext/twig/.gitignore +30 -0
  289. vendor/vendor/twig/twig/ext/twig/LICENSE +31 -0
  290. vendor/vendor/twig/twig/ext/twig/config.m4 +8 -0
  291. vendor/vendor/twig/twig/ext/twig/config.w32 +8 -0
  292. vendor/vendor/twig/twig/ext/twig/php_twig.h +31 -0
  293. vendor/vendor/twig/twig/ext/twig/twig.c +1101 -0
  294. vendor/vendor/twig/twig/lib/Twig/Autoloader.php +48 -0
  295. vendor/vendor/twig/twig/lib/Twig/Compiler.php +270 -0
  296. vendor/vendor/twig/twig/lib/Twig/CompilerInterface.php +35 -0
  297. vendor/vendor/twig/twig/lib/Twig/Environment.php +1254 -0
  298. vendor/vendor/twig/twig/lib/Twig/Error.php +248 -0
  299. vendor/vendor/twig/twig/lib/Twig/Error/Loader.php +31 -0
  300. vendor/vendor/twig/twig/lib/Twig/Error/Runtime.php +20 -0
  301. vendor/vendor/twig/twig/lib/Twig/Error/Syntax.php +20 -0
  302. vendor/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php +28 -0
  303. vendor/vendor/twig/twig/lib/Twig/ExpressionParser.php +598 -0
  304. vendor/vendor/twig/twig/lib/Twig/Extension.php +93 -0
  305. vendor/vendor/twig/twig/lib/Twig/Extension/Core.php +1463 -0
  306. vendor/vendor/twig/twig/lib/Twig/Extension/Debug.php +71 -0
  307. vendor/vendor/twig/twig/lib/Twig/Extension/Escaper.php +107 -0
  308. vendor/vendor/twig/twig/lib/Twig/Extension/Optimizer.php +35 -0
  309. vendor/vendor/twig/twig/lib/Twig/Extension/Sandbox.php +112 -0
  310. vendor/vendor/twig/twig/lib/Twig/Extension/Staging.php +113 -0
  311. vendor/vendor/twig/twig/lib/Twig/Extension/StringLoader.php +64 -0
  312. vendor/vendor/twig/twig/lib/Twig/ExtensionInterface.php +83 -0
  313. vendor/vendor/twig/twig/lib/Twig/Filter.php +81 -0
  314. vendor/vendor/twig/twig/lib/Twig/Filter/Function.php +37 -0
  315. vendor/vendor/twig/twig/lib/Twig/Filter/Method.php +39 -0
  316. vendor/vendor/twig/twig/lib/Twig/Filter/Node.php +39 -0
  317. vendor/vendor/twig/twig/lib/Twig/FilterCallableInterface.php +23 -0
  318. vendor/vendor/twig/twig/lib/Twig/FilterInterface.php +42 -0
  319. vendor/vendor/twig/twig/lib/Twig/Function.php +71 -0
  320. vendor/vendor/twig/twig/lib/Twig/Function/Function.php +38 -0
  321. vendor/vendor/twig/twig/lib/Twig/Function/Method.php +40 -0
  322. vendor/vendor/twig/twig/lib/Twig/Function/Node.php +39 -0
  323. vendor/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php +23 -0
  324. vendor/vendor/twig/twig/lib/Twig/FunctionInterface.php +39 -0
  325. vendor/vendor/twig/twig/lib/Twig/Lexer.php +409 -0
  326. vendor/vendor/twig/twig/lib/Twig/LexerInterface.php +31 -0
  327. vendor/vendor/twig/twig/lib/Twig/Loader/Array.php +95 -0
  328. vendor/vendor/twig/twig/lib/Twig/Loader/Chain.php +138 -0
  329. vendor/vendor/twig/twig/lib/Twig/Loader/Filesystem.php +229 -0
  330. vendor/vendor/twig/twig/lib/Twig/Loader/String.php +59 -0
  331. vendor/vendor/twig/twig/lib/Twig/LoaderInterface.php +52 -0
  332. vendor/vendor/twig/twig/lib/Twig/Markup.php +37 -0
  333. vendor/vendor/twig/twig/lib/Twig/Node.php +226 -0
  334. vendor/vendor/twig/twig/lib/Twig/Node/AutoEscape.php +39 -0
  335. vendor/vendor/twig/twig/lib/Twig/Node/Block.php +44 -0
  336. vendor/vendor/twig/twig/lib/Twig/Node/BlockReference.php +37 -0
  337. vendor/vendor/twig/twig/lib/Twig/Node/Body.php +19 -0
  338. vendor/vendor/twig/twig/lib/Twig/Node/Do.php +38 -0
  339. vendor/vendor/twig/twig/lib/Twig/Node/Embed.php +38 -0
  340. vendor/vendor/twig/twig/lib/Twig/Node/Expression.php +20 -0
  341. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Array.php +86 -0
  342. vendor/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php +28 -0
  343. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php +40 -0
  344. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php +18 -0
  345. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php +18 -0
  346. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php +18 -0
  347. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php +18 -0
  348. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php +18 -0
  349. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php +18 -0
  350. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php +18 -0
  351. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php +30 -0
  352. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php +17 -0
  353. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php +29 -0
  354. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php +17 -0
  355. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php +17 -0
  356. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php +33 -0
  357. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php +17 -0
  358. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php +17 -0
  359. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php +28 -0
  360. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php +18 -0
  361. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php +18 -0
  362. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php +17 -0
  363. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php +33 -0
  364. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php +18 -0
  365. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php +33 -0
  366. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php +33 -0
  367. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php +28 -0
  368. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php +18 -0
  369. vendor/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php +51 -0
  370. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Call.php +178 -0
  371. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php +31 -0
  372. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php +23 -0
  373. vendor/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php +33 -0
  374. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php +36 -0
  375. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php +43 -0
  376. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Function.php +35 -0
  377. vendor/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php +53 -0
  378. vendor/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php +41 -0
  379. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Name.php +88 -0
  380. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php +47 -0
  381. vendor/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php +26 -0
  382. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test.php +32 -0
  383. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php +46 -0
  384. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php +54 -0
  385. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php +33 -0
  386. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php +32 -0
  387. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php +31 -0
  388. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php +32 -0
  389. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php +29 -0
  390. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php +30 -0
  391. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php +18 -0
  392. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php +18 -0
  393. vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php +18 -0
  394. vendor/vendor/twig/twig/lib/Twig/Node/Flush.php +36 -0
  395. vendor/vendor/twig/twig/lib/Twig/Node/For.php +112 -0
  396. vendor/vendor/twig/twig/lib/Twig/Node/ForLoop.php +55 -0
  397. vendor/vendor/twig/twig/lib/Twig/Node/If.php +66 -0
  398. vendor/vendor/twig/twig/lib/Twig/Node/Import.php +50 -0
  399. vendor/vendor/twig/twig/lib/Twig/Node/Include.php +99 -0
  400. vendor/vendor/twig/twig/lib/Twig/Node/Macro.php +96 -0
  401. vendor/vendor/twig/twig/lib/Twig/Node/Module.php +383 -0
  402. vendor/vendor/twig/twig/lib/Twig/Node/Print.php +39 -0
  403. vendor/vendor/twig/twig/lib/Twig/Node/Sandbox.php +47 -0
  404. vendor/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php +60 -0
  405. vendor/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php +59 -0
  406. vendor/vendor/twig/twig/lib/Twig/Node/Set.php +61 -0
functions/integrations/wpcli-timber.php CHANGED
@@ -44,7 +44,7 @@ if (class_exists('WP_CLI_Command')) {
44
  $message = 'Failed to clear timber cache';
45
  if ($clear){
46
  $message = "Cleared contents of Timber's Cache";
47
- WP_CLI::success($messsage);
48
  } else {
49
  WP_CLI::warning($message);
50
  }
44
  $message = 'Failed to clear timber cache';
45
  if ($clear){
46
  $message = "Cleared contents of Timber's Cache";
47
+ WP_CLI::success($message);
48
  } else {
49
  WP_CLI::warning($message);
50
  }
functions/timber-archives.php CHANGED
@@ -25,6 +25,7 @@ class TimberArchives extends TimberCore
25
  * @return mixed
26
  */
27
  function get_archives_link($url, $text) {
 
28
  $ret['text'] = $ret['title'] = $ret['name'] = wptexturize($text);
29
  $ret['url'] = $ret['link'] = esc_url(TimberURLHelper::prepend_to_url($url, $this->base));
30
  return $ret;
@@ -204,6 +205,7 @@ class TimberArchives extends TimberCore
204
  $key = "wp_get_archives:$key:$last_changed";
205
  if (!$results = wp_cache_get($key, 'posts')) {
206
  $results = $wpdb->get_results($query);
 
207
  $cache[$key] = $results;
208
  wp_cache_set($key, $results, 'posts');
209
  }
25
  * @return mixed
26
  */
27
  function get_archives_link($url, $text) {
28
+ $ret = array();
29
  $ret['text'] = $ret['title'] = $ret['name'] = wptexturize($text);
30
  $ret['url'] = $ret['link'] = esc_url(TimberURLHelper::prepend_to_url($url, $this->base));
31
  return $ret;
205
  $key = "wp_get_archives:$key:$last_changed";
206
  if (!$results = wp_cache_get($key, 'posts')) {
207
  $results = $wpdb->get_results($query);
208
+ $cache = array();
209
  $cache[$key] = $results;
210
  wp_cache_set($key, $results, 'posts');
211
  }
functions/timber-comment.php CHANGED
@@ -14,6 +14,7 @@ class TimberComment extends TimberCore implements TimberCoreInterface {
14
  public $comment_date;
15
  public $comment_ID;
16
  public $user_id;
 
17
 
18
  /**
19
  * @param int $cid
@@ -27,7 +28,7 @@ class TimberComment extends TimberCore implements TimberCoreInterface {
27
  }
28
 
29
  /**
30
- * @param mixed $cid
31
  */
32
  function init($cid) {
33
  $comment_data = $cid;
14
  public $comment_date;
15
  public $comment_ID;
16
  public $user_id;
17
+ public $comment_author;
18
 
19
  /**
20
  * @param int $cid
28
  }
29
 
30
  /**
31
+ * @param integer $cid
32
  */
33
  function init($cid) {
34
  $comment_data = $cid;
functions/timber-core-interface.php CHANGED
@@ -6,6 +6,9 @@ interface TimberCoreInterface {
6
 
7
  public function __get( $field );
8
 
 
 
 
9
  public function __isset( $field );
10
 
11
  public function meta( $key );
6
 
7
  public function __get( $field );
8
 
9
+ /**
10
+ * @return boolean
11
+ */
12
  public function __isset( $field );
13
 
14
  public function meta( $key );
functions/timber-core.php CHANGED
@@ -5,6 +5,7 @@ abstract class TimberCore {
5
  public $id;
6
  public $ID;
7
  public $object_type;
 
8
 
9
  /**
10
  *
@@ -19,7 +20,7 @@ abstract class TimberCore {
19
  }
20
 
21
  /**
22
- * This is helpful for twig to return properties and methods see: https://github.com/fabpot/Twig/issues/2
23
  * @return mixed
24
  */
25
  function __call( $field, $args ) {
@@ -27,21 +28,21 @@ abstract class TimberCore {
27
  }
28
 
29
  /**
30
- * This is helpful for twig to return properties and methods see: https://github.com/fabpot/Twig/issues/2
31
  *
32
  * @return mixed
33
  */
34
  function __get( $field ) {
35
- if ( !isset( $this->$field ) ) {
36
- if ( $meta_value = $this->meta( $field ) ) {
37
- $this->$field = $meta_value;
38
- } else if (method_exists($this, $field)){
39
- $this->$field = $this->$field();
40
- } else {
41
- $this->$field = false;
42
- }
43
  }
44
- return $this->$field;
 
 
 
 
 
 
45
  }
46
 
47
  /**
@@ -49,13 +50,15 @@ abstract class TimberCore {
49
  *
50
  * @param array|object $info an object or array you want to grab data from to attach to the Timber object
51
  */
52
- function import( $info ) {
53
  if ( is_object( $info ) ) {
54
  $info = get_object_vars( $info );
55
  }
56
  if ( is_array( $info ) ) {
57
  foreach ( $info as $key => $value ) {
58
- if ( !empty( $key ) ) {
 
 
59
  $this->$key = $value;
60
  }
61
  }
5
  public $id;
6
  public $ID;
7
  public $object_type;
8
+ public $_can_edit;
9
 
10
  /**
11
  *
20
  }
21
 
22
  /**
23
+ * This is helpful for twig to return properties and methods see: https://github.com/fabpot/Twig/issues/2
24
  * @return mixed
25
  */
26
  function __call( $field, $args ) {
28
  }
29
 
30
  /**
31
+ * This is helpful for twig to return properties and methods see: https://github.com/fabpot/Twig/issues/2
32
  *
33
  * @return mixed
34
  */
35
  function __get( $field ) {
36
+ if ( isset( $this->$field ) ) {
37
+ return $this->$field;
 
 
 
 
 
 
38
  }
39
+ if ( $meta_value = $this->meta( $field ) ) {
40
+ return $this->$field = $meta_value;
41
+ }
42
+ if (method_exists($this, $field)) {
43
+ return $this->$field = $this->$field();
44
+ }
45
+ return $this->$field = false;
46
  }
47
 
48
  /**
50
  *
51
  * @param array|object $info an object or array you want to grab data from to attach to the Timber object
52
  */
53
+ function import( $info, $force = false ) {
54
  if ( is_object( $info ) ) {
55
  $info = get_object_vars( $info );
56
  }
57
  if ( is_array( $info ) ) {
58
  foreach ( $info as $key => $value ) {
59
+ if ( !empty( $key ) && $force ) {
60
+ $this->$key = $value;
61
+ } else if ( !empty( $key ) && !method_exists($this, $key) ){
62
  $this->$key = $value;
63
  }
64
  }
functions/timber-helper.php CHANGED
@@ -13,10 +13,9 @@ class TimberHelper {
13
  * @return mixed
14
  */
15
  public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
 
16
  if ( $transient_time === false || ( defined( 'WP_DISABLE_TRANSIENTS' ) && WP_DISABLE_TRANSIENTS ) ) {
17
  $enable_transients = false;
18
- } else {
19
- $enable_transients = true;
20
  }
21
 
22
  $data = $enable_transients ? get_transient( $slug ) : false;
@@ -52,14 +51,24 @@ class TimberHelper {
52
  return $data;
53
  }
54
 
 
 
 
 
55
  public static function _lock_transient( $slug, $lock_timeout ) {
56
  set_transient( $slug . '_lock', true, $lock_timeout );
57
  }
58
 
 
 
 
59
  public static function _unlock_transient( $slug ) {
60
  delete_transient( $slug . '_lock', true );
61
  }
62
 
 
 
 
63
  public static function _is_transient_locked( $slug ) {
64
  return (bool)get_transient( $slug . '_lock' );
65
  }
@@ -115,7 +124,7 @@ class TimberHelper {
115
  *
116
  *
117
  * @param string $function_name
118
- * @param array $defaults
119
  * @param bool $return_output_buffer
120
  * @return TimberFunctionWrapper
121
  */
@@ -231,7 +240,7 @@ class TimberHelper {
231
  *
232
  *
233
  * @param string $ret
234
- * @return mixed
235
  * @deprecated since 0.20.0
236
  */
237
  public static function twitterify( $ret ) {
@@ -241,7 +250,7 @@ class TimberHelper {
241
  $pattern .= '[a-wyz][a-z](fo|g|l|m|mes|o|op|pa|ro|seum|t|u|v|z)?)#i';
242
  $ret = preg_replace( $pattern, '<a href="mailto:\\1">\\1</a>', $ret );
243
  $ret = preg_replace( "/\B@(\w+)/", " <a href=\"http://www.twitter.com/\\1\" target=\"_blank\">@\\1</a>", $ret );
244
- $ret = preg_replace( "/\B#(\w+)/", " <a href=\"http://search.twitter.com/search?q=\\1\" target=\"_blank\">#\\1</a>", $ret );
245
  return $ret;
246
  }
247
 
@@ -573,7 +582,7 @@ class TimberHelper {
573
  }
574
 
575
  /* LEGACY These have since been re-organized; but keeping linkages for backwards-compatibility */
576
-
577
  /**
578
  * @deprecated
579
  */
13
  * @return mixed
14
  */
15
  public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
16
+ $enable_transients = true;
17
  if ( $transient_time === false || ( defined( 'WP_DISABLE_TRANSIENTS' ) && WP_DISABLE_TRANSIENTS ) ) {
18
  $enable_transients = false;
 
 
19
  }
20
 
21
  $data = $enable_transients ? get_transient( $slug ) : false;
51
  return $data;
52
  }
53
 
54
+ /**
55
+ * @param string $slug
56
+ * @param integer $lock_timeout
57
+ */
58
  public static function _lock_transient( $slug, $lock_timeout ) {
59
  set_transient( $slug . '_lock', true, $lock_timeout );
60
  }
61
 
62
+ /**
63
+ * @param string $slug
64
+ */
65
  public static function _unlock_transient( $slug ) {
66
  delete_transient( $slug . '_lock', true );
67
  }
68
 
69
+ /**
70
+ * @param string $slug
71
+ */
72
  public static function _is_transient_locked( $slug ) {
73
  return (bool)get_transient( $slug . '_lock' );
74
  }
124
  *
125
  *
126
  * @param string $function_name
127
+ * @param integer[] $defaults
128
  * @param bool $return_output_buffer
129
  * @return TimberFunctionWrapper
130
  */
240
  *
241
  *
242
  * @param string $ret
243
+ * @return string
244
  * @deprecated since 0.20.0
245
  */
246
  public static function twitterify( $ret ) {
250
  $pattern .= '[a-wyz][a-z](fo|g|l|m|mes|o|op|pa|ro|seum|t|u|v|z)?)#i';
251
  $ret = preg_replace( $pattern, '<a href="mailto:\\1">\\1</a>', $ret );
252
  $ret = preg_replace( "/\B@(\w+)/", " <a href=\"http://www.twitter.com/\\1\" target=\"_blank\">@\\1</a>", $ret );
253
+ $ret = preg_replace( "/\B#(\w+)/", " <a href=\"http://twitter.com/search?q=\\1\" target=\"_blank\">#\\1</a>", $ret );
254
  return $ret;
255
  }
256
 
582
  }
583
 
584
  /* LEGACY These have since been re-organized; but keeping linkages for backwards-compatibility */
585
+
586
  /**
587
  * @deprecated
588
  */
functions/timber-image-helper.php CHANGED
@@ -57,6 +57,9 @@ class TimberImageHelper
57
  self::delete_letterboxed_files($local);
58
  }
59
 
 
 
 
60
  static function delete_resized_files($local_file) {
61
  $info = pathinfo($local_file);
62
  $dir = $info['dirname'];
@@ -76,6 +79,9 @@ class TimberImageHelper
76
  }
77
  }
78
 
 
 
 
79
  static function delete_letterboxed_files($local_file) {
80
  $info = pathinfo($local_file);
81
  $dir = $info['dirname'];
@@ -136,7 +142,7 @@ class TimberImageHelper
136
  * @param string $src
137
  * @param int $w
138
  * @param int $h
139
- * @param $color
140
  * @return string
141
  */
142
  static function get_letterbox_file_name_relative_to_content($src, $w, $h, $color) {
@@ -192,6 +198,9 @@ class TimberImageHelper
192
  return $dir_relative_to_content . '/' . $new_name;
193
  }
194
 
 
 
 
195
  public static function in_uploads($src) {
196
  $upload_dir = wp_upload_dir();
197
  if (strstr($src, $upload_dir['relative'])) {
@@ -225,6 +234,9 @@ class TimberImageHelper
225
  return self::get_rel_path($src);
226
  }
227
 
 
 
 
228
  public static function get_server_location($url) {
229
  $upload_dir = wp_upload_dir();
230
  $abs = false;
@@ -383,6 +395,7 @@ class TimberImageHelper
383
  }
384
  $tmp = download_url($file);
385
  preg_match('/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches);
 
386
  $file_array['name'] = basename($matches[0]);
387
  $file_array['tmp_name'] = $tmp;
388
  // If error storing temporarily, unlink
57
  self::delete_letterboxed_files($local);
58
  }
59
 
60
+ /**
61
+ * @param string $local_file
62
+ */
63
  static function delete_resized_files($local_file) {
64
  $info = pathinfo($local_file);
65
  $dir = $info['dirname'];
79
  }
80
  }
81
 
82
+ /**
83
+ * @param string $local_file
84
+ */
85
  static function delete_letterboxed_files($local_file) {
86
  $info = pathinfo($local_file);
87
  $dir = $info['dirname'];
142
  * @param string $src
143
  * @param int $w
144
  * @param int $h
145
+ * @param string $color
146
  * @return string
147
  */
148
  static function get_letterbox_file_name_relative_to_content($src, $w, $h, $color) {
198
  return $dir_relative_to_content . '/' . $new_name;
199
  }
200
 
201
+ /**
202
+ * @param string $src
203
+ */
204
  public static function in_uploads($src) {
205
  $upload_dir = wp_upload_dir();
206
  if (strstr($src, $upload_dir['relative'])) {
234
  return self::get_rel_path($src);
235
  }
236
 
237
+ /**
238
+ * @param string $url
239
+ */
240
  public static function get_server_location($url) {
241
  $upload_dir = wp_upload_dir();
242
  $abs = false;
395
  }
396
  $tmp = download_url($file);
397
  preg_match('/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches);
398
+ $file_array = array();
399
  $file_array['name'] = basename($matches[0]);
400
  $file_array['tmp_name'] = $tmp;
401
  // If error storing temporarily, unlink
functions/timber-image.php CHANGED
@@ -15,6 +15,7 @@ class TimberImage extends TimberPost implements TimberCoreInterface {
15
  public $sizes = array();
16
  public $post_parent;
17
  public $caption;
 
18
 
19
  /**
20
  * @param int $iid
@@ -167,30 +168,14 @@ class TimberImage extends TimberPost implements TimberCoreInterface {
167
  if (strstr($iid, '://')) {
168
  $this->init_with_url($iid);
169
  return;
170
- } else if (strstr(strtolower($iid), '.jpg')) {
171
- $this->init_with_url($iid);
172
- }
173
- }
174
- $image_info = $iid;
175
- if (is_numeric($iid)) {
176
- $image_info = wp_get_attachment_metadata($iid);
177
- if (!is_array($image_info)) {
178
- $image_info = array();
179
  }
180
- $image_custom = get_post_custom($iid);
181
- $basic = get_post($iid);
182
- if ($basic) {
183
- if (isset($basic->post_excerpt)) {
184
- $this->caption = $basic->post_excerpt;
185
- }
186
- $image_custom = array_merge($image_custom, get_object_vars($basic));
187
  }
188
- $image_info = array_merge($image_info, $image_custom);
189
- } else if (is_array($image_info) && isset($image_info['image'])) {
190
- $image_info = $image_info['image'];
191
- } else if (is_object($image_info)) {
192
- $image_info = get_object_vars($image_info);
193
  }
 
 
 
194
  $this->import($image_info);
195
  $basedir = self::wp_upload_dir();
196
  $basedir = $basedir['basedir'];
@@ -220,6 +205,32 @@ class TimberImage extends TimberPost implements TimberCoreInterface {
220
  }
221
  }
222
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  /**
224
  * @param string $url
225
  */
15
  public $sizes = array();
16
  public $post_parent;
17
  public $caption;
18
+ public $_wp_attached_file;
19
 
20
  /**
21
  * @param int $iid
168
  if (strstr($iid, '://')) {
169
  $this->init_with_url($iid);
170
  return;
 
 
 
 
 
 
 
 
 
171
  }
172
+ if (strstr(strtolower($iid), '.jpg')) {
173
+ $this->init_with_url($iid);
 
 
 
 
 
174
  }
 
 
 
 
 
175
  }
176
+
177
+ $image_info = $this->get_image_info($iid);
178
+
179
  $this->import($image_info);
180
  $basedir = self::wp_upload_dir();
181
  $basedir = $basedir['basedir'];
205
  }
206
  }
207
 
208
+ private function get_image_info($iid) {
209
+ $image_info = $iid;
210
+ if (is_numeric($iid)) {
211
+ $image_info = wp_get_attachment_metadata($iid);
212
+ if (!is_array($image_info)) {
213
+ $image_info = array();
214
+ }
215
+ $image_custom = get_post_custom($iid);
216
+ $basic = get_post($iid);
217
+ if ($basic) {
218
+ if (isset($basic->post_excerpt)) {
219
+ $this->caption = $basic->post_excerpt;
220
+ }
221
+ $image_custom = array_merge($image_custom, get_object_vars($basic));
222
+ }
223
+ return array_merge($image_info, $image_custom);
224
+ }
225
+ if (is_array($image_info) && isset($image_info['image'])) {
226
+ return $image_info['image'];
227
+ }
228
+ if (is_object($image_info)) {
229
+ return get_object_vars($image_info);
230
+ }
231
+ return $iid;
232
+ }
233
+
234
  /**
235
  * @param string $url
236
  */
functions/timber-loader.php CHANGED
@@ -71,7 +71,7 @@ class TimberLoader {
71
  $this->set_cache($key, $output, self::CACHEGROUP, $expires, $cache_mode);
72
  }
73
 
74
- return $output;
75
  }
76
 
77
  /**
@@ -133,7 +133,7 @@ class TimberLoader {
133
 
134
  /**
135
  * returns an array of the directory inside themes that holds twig files
136
- * @return array the names of directores, ie: array('templats', 'views');
137
  */
138
  private function get_locations_theme_dir() {
139
  if (is_string(Timber::$dirname)) {
@@ -201,7 +201,7 @@ class TimberLoader {
201
  }
202
 
203
  /**
204
- * @return Twig_Loader_Chain
205
  */
206
  function get_loader() {
207
  $paths = array();
@@ -290,6 +290,9 @@ class TimberLoader {
290
  return false;
291
  }
292
 
 
 
 
293
  public static function rrmdir($dirPath) {
294
  if (! is_dir($dirPath)) {
295
  throw new InvalidArgumentException("$dirPath must be a directory");
@@ -356,11 +359,11 @@ class TimberLoader {
356
 
357
  /**
358
  * @param string $key
359
- * @param mixed $value
360
  * @param string $group
361
  * @param int $expires
362
  * @param string $cache_mode
363
- * @return mixed
364
  */
365
  public function set_cache($key, $value, $group = self::CACHEGROUP, $expires = 0, $cache_mode = self::CACHE_USE_DEFAULT) {
366
  $object_cache = false;
71
  $this->set_cache($key, $output, self::CACHEGROUP, $expires, $cache_mode);
72
  }
73
 
74
+ return apply_filters('timber_output', $output);
75
  }
76
 
77
  /**
133
 
134
  /**
135
  * returns an array of the directory inside themes that holds twig files
136
+ * @return string[] the names of directores, ie: array('templats', 'views');
137
  */
138
  private function get_locations_theme_dir() {
139
  if (is_string(Timber::$dirname)) {
201
  }
202
 
203
  /**
204
+ * @return Twig_Loader_Filesystem
205
  */
206
  function get_loader() {
207
  $paths = array();
290
  return false;
291
  }
292
 
293
+ /**
294
+ * @param string|false $dirPath
295
+ */
296
  public static function rrmdir($dirPath) {
297
  if (! is_dir($dirPath)) {
298
  throw new InvalidArgumentException("$dirPath must be a directory");
359
 
360
  /**
361
  * @param string $key
362
+ * @param string|boolean $value
363
  * @param string $group
364
  * @param int $expires
365
  * @param string $cache_mode
366
+ * @return string|boolean
367
  */
368
  public function set_cache($key, $value, $group = self::CACHEGROUP, $expires = 0, $cache_mode = self::CACHE_USE_DEFAULT) {
369
  $object_cache = false;
functions/timber-menu-item.php CHANGED
@@ -225,4 +225,10 @@ class TimberMenuItem extends TimberCore implements TimberCoreInterface {
225
  return $this->get_link();
226
  }
227
 
 
 
 
 
 
 
228
  }
225
  return $this->get_link();
226
  }
227
 
228
+ public function title() {
229
+ if (isset($this->__title)){
230
+ return $this->__title;
231
+ }
232
+ }
233
+
234
  }
functions/timber-menu.php CHANGED
@@ -10,6 +10,7 @@ class TimberMenu extends TimberCore {
10
  public $ID = null;
11
  public $name = null;
12
  public $term_id;
 
13
 
14
  /**
15
  * @param int $slug
@@ -28,6 +29,7 @@ class TimberMenu extends TimberCore {
28
  if ($menu_id) {
29
  $this->init($menu_id);
30
  } else {
 
31
  //TimberHelper::error_log("Sorry, the menu you were looking for wasn't found ('" . $slug . "'). Here's what Timber did find:");
32
  }
33
  return null;
@@ -52,10 +54,24 @@ class TimberMenu extends TimberCore {
52
  }
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  /**
56
  * @param string $slug
57
  * @param array $locations
58
- * @return mixed
59
  */
60
  private function get_menu_id_from_locations($slug, $locations) {
61
  if ($slug === 0) {
@@ -117,6 +133,11 @@ class TimberMenu extends TimberCore {
117
  $index = array();
118
  $menu = array();
119
  foreach ($items as $item) {
 
 
 
 
 
120
  if(isset($item->ID)){
121
  if (is_object($item) && get_class($item) == 'WP_Post'){
122
  $old_menu_item = $item;
10
  public $ID = null;
11
  public $name = null;
12
  public $term_id;
13
+ public $title;
14
 
15
  /**
16
  * @param int $slug
29
  if ($menu_id) {
30
  $this->init($menu_id);
31
  } else {
32
+ $this->init_as_page_menu();
33
  //TimberHelper::error_log("Sorry, the menu you were looking for wasn't found ('" . $slug . "'). Here's what Timber did find:");
34
  }
35
  return null;
54
  }
55
  }
56
 
57
+ private function init_as_page_menu() {
58
+ $menu = get_pages();
59
+ if ($menu) {
60
+ foreach($menu as $mi) {
61
+ $mi->__title = $mi->post_title;
62
+ }
63
+ _wp_menu_item_classes_by_context($menu);
64
+ if (is_array($menu)){
65
+ $menu = self::order_children($menu);
66
+ }
67
+ $this->items = $menu;
68
+ }
69
+ }
70
+
71
  /**
72
  * @param string $slug
73
  * @param array $locations
74
+ * @return integer
75
  */
76
  private function get_menu_id_from_locations($slug, $locations) {
77
  if ($slug === 0) {
133
  $index = array();
134
  $menu = array();
135
  foreach ($items as $item) {
136
+ if (isset($item->title)) {
137
+ //items from wp can come with a $title property which conflicts with methods
138
+ $item->__title = $item->title;
139
+ unset($item->title);
140
+ }
141
  if(isset($item->ID)){
142
  if (is_object($item) && get_class($item) == 'WP_Post'){
143
  $old_menu_item = $item;
functions/timber-post-getter.php CHANGED
@@ -39,7 +39,7 @@ class TimberPostGetter {
39
  $query = false;
40
  }
41
 
42
- if (is_object($query) && !is_a('WP_Query' ) ){
43
  // The only object other than a query is a type of post object
44
  $query = array( $query );
45
  }
@@ -68,7 +68,7 @@ class TimberPostGetter {
68
  /**
69
  * @param array $results
70
  * @param string $PostClass
71
- * @return array
72
  */
73
  static function handle_post_results($results, $PostClass = 'TimberPost') {
74
  $posts = array();
39
  $query = false;
40
  }
41
 
42
+ if (is_object($query) && !is_a($query, 'WP_Query') ){
43
  // The only object other than a query is a type of post object
44
  $query = array( $query );
45
  }
68
  /**
69
  * @param array $results
70
  * @param string $PostClass
71
+ * @return TimberPostsCollection
72
  */
73
  static function handle_post_results($results, $PostClass = 'TimberPost') {
74
  $posts = array();
functions/timber-post.php CHANGED
@@ -13,6 +13,9 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
13
  public $_content;
14
  public $_get_terms;
15
 
 
 
 
16
  public $class;
17
  public $display_date;
18
  public $id;
@@ -30,7 +33,11 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
30
  * @return \TimberPost TimberPost object -- woo!
31
  */
32
  function __construct($pid = null) {
33
- if ($pid === null && get_the_ID()) {
 
 
 
 
34
  $pid = get_the_ID();
35
  $this->ID = $pid;
36
  } else if ($pid === null && ($pid_from_loop = TimberPostGetter::loop_to_id())) {
@@ -117,7 +124,7 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
117
  /**
118
  * helps you find the post id regardless of whetehr you send a string or whatever
119
  *
120
- * @param mixed $pid ;
121
  * @return integer ID number of a post
122
  */
123
  private function check_post_id($pid) {
@@ -139,7 +146,7 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
139
  /**
140
  * get_post_id_by_name($post_name)
141
  *
142
- * @param $post_name
143
  * @return int
144
  */
145
  public static function get_post_id_by_name($post_name) {
@@ -306,6 +313,7 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
306
  } else {
307
  $adjacent = get_adjacent_post(false, '', false);
308
  }
 
309
  if ($adjacent) {
310
  $this->_next[$taxonomy] = new $this->PostClass($adjacent);
311
  } else {
@@ -371,25 +379,21 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
371
  * @return mixed
372
  */
373
  function get_prev($taxonomy = false) {
374
- if (!isset($this->_prev) || !isset($this->_prev[$taxonomy])) {
375
- global $post;
376
- $this->_prev = array();
377
- $old_global = $post;
378
- $post = $this;
379
- $in_same_cat = false;
380
- if ($taxonomy) {
381
- $adjacent = get_adjacent_post(true, '', true, $taxonomy);
382
- } else {
383
- $adjacent = get_adjacent_post(false, '', true);
384
- }
385
-
386
- if ($adjacent) {
387
- $this->_prev[$taxonomy] = new $this->PostClass($adjacent);
388
- } else {
389
- $this->_prev[$taxonomy] = false;
390
- }
391
- $post = $old_global;
392
  }
 
 
 
 
 
 
 
 
 
 
 
 
393
  return $this->_prev[$taxonomy];
394
  }
395
 
@@ -439,14 +443,15 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
439
  $post->id = $post->ID;
440
  $post->slug = $post->post_name;
441
  $customs = $this->get_post_custom($post->ID);
442
- $post = (object)array_merge((array)$post, (array)$customs);
 
443
  return $post;
444
  }
445
 
446
  /**
447
  * This is deprecated!
448
  * @param string $use
449
- * @return bool|string
450
  */
451
  function get_display_date($use = 'post_date') {
452
  return date(get_option('date_format'), strtotime($this->$use));
@@ -668,8 +673,7 @@ class TimberPost extends TimberCore implements TimberCoreInterface {
668
  * @return string
669
  */
670
  function get_title() {
671
- $title = $this->post_title;
672
- return apply_filters('the_title', $title);
673
  }
674
 
675
  /**
13
  public $_content;
14
  public $_get_terms;
15
 
16
+ private $_next = array();
17
+ private $_prev = array();
18
+
19
  public $class;
20
  public $display_date;
21
  public $id;
33
  * @return \TimberPost TimberPost object -- woo!
34
  */
35
  function __construct($pid = null) {
36
+ global $wp_query;
37
+ if ($pid === null && isset($wp_query->queried_object_id) && $wp_query->queried_object_id) {
38
+ $pid = $wp_query->queried_object_id;
39
+ $this->ID = $pid;
40
+ } else if ($pid === null && get_the_ID()) {
41
  $pid = get_the_ID();
42
  $this->ID = $pid;
43
  } else if ($pid === null && ($pid_from_loop = TimberPostGetter::loop_to_id())) {
124
  /**
125
  * helps you find the post id regardless of whetehr you send a string or whatever
126
  *
127
+ * @param integer $pid ;
128
  * @return integer ID number of a post
129
  */
130
  private function check_post_id($pid) {
146
  /**
147
  * get_post_id_by_name($post_name)
148
  *
149
+ * @param string $post_name
150
  * @return int
151
  */
152
  public static function get_post_id_by_name($post_name) {
313
  } else {
314
  $adjacent = get_adjacent_post(false, '', false);
315
  }
316
+
317
  if ($adjacent) {
318
  $this->_next[$taxonomy] = new $this->PostClass($adjacent);
319
  } else {
379
  * @return mixed
380
  */
381
  function get_prev($taxonomy = false) {
382
+ if (isset($this->_prev) && isset($this->_prev[$taxonomy])) {
383
+ return $this->_prev[$taxonomy];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
384
  }
385
+ global $post;
386
+ $old_global = $post;
387
+ $post = $this;
388
+ $within_taxonomy = ($taxonomy) ? $taxonomy : 'category';
389
+ $adjacent = get_adjacent_post(($taxonomy), '', true, $within_taxonomy);
390
+
391
+ $prev_in_taxonomy = false;
392
+ if ($adjacent) {
393
+ $prev_in_taxonomy = new $this->PostClass($adjacent);
394
+ }
395
+ $this->_prev[$taxonomy] = $prev_in_taxonomy;
396
+ $post = $old_global;
397
  return $this->_prev[$taxonomy];
398
  }
399
 
443
  $post->id = $post->ID;
444
  $post->slug = $post->post_name;
445
  $customs = $this->get_post_custom($post->ID);
446
+ $post->custom = $customs;
447
+ $post = (object)array_merge((array)$customs, (array)$post);
448
  return $post;
449
  }
450
 
451
  /**
452
  * This is deprecated!
453
  * @param string $use
454
+ * @return string
455
  */
456
  function get_display_date($use = 'post_date') {
457
  return date(get_option('date_format'), strtotime($this->$use));
673
  * @return string
674
  */
675
  function get_title() {
676
+ return apply_filters('the_title', $this->post_title, $this->ID);
 
677
  }
678
 
679
  /**
functions/timber-routes.php CHANGED
@@ -20,6 +20,10 @@ class TimberRoutes {
20
  }
21
  }
22
 
 
 
 
 
23
  public static function add_route($route, $callback, $args = array()) {
24
  global $timber;
25
  if (!isset($timber->router)) {
20
  }
21
  }
22
 
23
+ /**
24
+ * @param string $route
25
+ * @param callable $callback
26
+ */
27
  public static function add_route($route, $callback, $args = array()) {
28
  global $timber;
29
  if (!isset($timber->router)) {
functions/timber-site.php CHANGED
@@ -15,6 +15,7 @@ class TimberSite extends TimberCore implements TimberCoreInterface {
15
  public $siteurl;
16
  public $theme;
17
  public $title;
 
18
 
19
  /**
20
  *
15
  public $siteurl;
16
  public $theme;
17
  public $title;
18
+ public $url;
19
 
20
  /**
21
  *
functions/timber-term-getter.php CHANGED
@@ -51,7 +51,7 @@ class TimberTermGetter
51
  /**
52
  * @param string|array $taxonomies
53
  * @param string|array $args
54
- * @param $TermClass
55
  * @return mixed
56
  */
57
  public static function handle_term_query($taxonomies, $args, $TermClass){
@@ -140,7 +140,7 @@ class TimberTermGetter
140
  }
141
 
142
  /**
143
- * @param array $args
144
  * @return stdClass
145
  */
146
  public static function get_term_query_from_array_of_ids($args) {
@@ -151,7 +151,7 @@ class TimberTermGetter
151
  }
152
 
153
  /**
154
- * @param array $args
155
  * @return stdClass
156
  */
157
  public static function get_term_query_from_array_of_strings($args) {
51
  /**
52
  * @param string|array $taxonomies
53
  * @param string|array $args
54
+ * @param string $TermClass
55
  * @return mixed
56
  */
57
  public static function handle_term_query($taxonomies, $args, $TermClass){
140
  }
141
 
142
  /**
143
+ * @param integer[] $args
144
  * @return stdClass
145
  */
146
  public static function get_term_query_from_array_of_ids($args) {
151
  }
152
 
153
  /**
154
+ * @param string[] $args
155
  * @return stdClass
156
  */
157
  public static function get_term_query_from_array_of_strings($args) {
functions/timber-term.php CHANGED
@@ -39,7 +39,7 @@ class TimberTerm extends TimberCore implements TimberCoreInterface {
39
  ===================== */
40
 
41
  /**
42
- * @return mixed
43
  */
44
  private function get_term_from_query() {
45
  global $wp_query;
@@ -276,7 +276,7 @@ class TimberTerm extends TimberCore implements TimberCoreInterface {
276
 
277
  /**
278
  * @param string $field_name
279
- * @return mixed
280
  */
281
  public function meta($field_name) {
282
  return $this->get_meta_field($field_name);
39
  ===================== */
40
 
41
  /**
42
+ * @return integer
43
  */
44
  private function get_term_from_query() {
45
  global $wp_query;
276
 
277
  /**
278
  * @param string $field_name
279
+ * @return string
280
  */
281
  public function meta($field_name) {
282
  return $this->get_meta_field($field_name);
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
- Stable tag: 0.20.6
6
  Tested up to: 4.0
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
@@ -41,7 +41,18 @@ Timber is great for any WordPress developer who cares about writing good, mainta
41
 
42
  == Changelog ==
43
 
44
- = 0.20.6
 
 
 
 
 
 
 
 
 
 
 
45
  * Fixed some resulting bugs from numberposts vs. posts_per_page change as relates to galleries (thanks @IJMacD)
46
  * Fixed issue with author.php in starter theme (thanks @dmtroyer)
47
  * Added some sanity checks when menus are missing (thanks @jaredNova)
2
  Contributors: jarednova
3
  Tags: template engine, templates, twig
4
  Requires at least: 3.7
5
+ Stable tag: 0.20.7
6
  Tested up to: 4.0
7
  PHP version: 5.3.0 or greater
8
  License: GPLv2 or later
41
 
42
  == Changelog ==
43
 
44
+ = 0.20.7 =
45
+ * Cleaned-up logic for {{post.next}} and {{post.prev}} (thanks @alexlrobertson)
46
+ * Simplifiying internals of TimberCore, TimberPost (thanks @alexlrobertson)
47
+ * Initialization of variables from stolen WP functions (thanks @alexlrobertson)
48
+ * Fixed Twitter API call (thanks @asecondwill)
49
+ * Matched TimberMenu fallback behavior to grab pages_men (@jaredNova)
50
+ * Fixed a bug with the_title filter (thanks @kuus)
51
+ * Fixed weird conflicts when ACF names match methods (@jaredNova)
52
+ * Added a filter for timber_output (thanks @aristath)
53
+ * Fix for galleries showing only 5 images (thanks @IJMacD)
54
+
55
+ = 0.20.6 =
56
  * Fixed some resulting bugs from numberposts vs. posts_per_page change as relates to galleries (thanks @IJMacD)
57
  * Fixed issue with author.php in starter theme (thanks @dmtroyer)
58
  * Added some sanity checks when menus are missing (thanks @jaredNova)
timber-starter-theme/timber-starter-theme/404.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The template for displaying 404 pages (Not Found)
4
+ *
5
+ * Methods for TimberHelper can be found in the /functions sub-directory
6
+ *
7
+ * @package WordPress
8
+ * @subpackage Timber
9
+ * @since Timber 0.1
10
+ */
11
+
12
+ $context = Timber::get_context();
13
+ Timber::render('404.twig', $context);
timber-starter-theme/timber-starter-theme/archive.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The template for displaying Archive pages.
4
+ *
5
+ * Used to display archive-type pages if nothing more specific matches a query.
6
+ * For example, puts together date-based pages if no date.php file exists.
7
+ *
8
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
9
+ *
10
+ * Methods for TimberHelper can be found in the /functions sub-directory
11
+ *
12
+ * @package WordPress
13
+ * @subpackage Timber
14
+ * @since Timber 0.2
15
+ */
16
+
17
+ $templates = array('archive.twig', 'index.twig');
18
+
19
+ $data = Timber::get_context();
20
+
21
+ $data['title'] = 'Archive';
22
+ if (is_day()){
23
+ $data['title'] = 'Archive: '.get_the_date( 'D M Y' );
24
+ } else if (is_month()){
25
+ $data['title'] = 'Archive: '.get_the_date( 'M Y' );
26
+ } else if (is_year()){
27
+ $data['title'] = 'Archive: '.get_the_date( 'Y' );
28
+ } else if (is_tag()){
29
+ $data['title'] = single_tag_title('', false);
30
+ } else if (is_category()){
31
+ $data['title'] = single_cat_title('', false);
32
+ array_unshift($templates, 'archive-'.get_query_var('cat').'.twig');
33
+ } else if (is_post_type_archive()){
34
+ $data['title'] = post_type_archive_title('', false);
35
+ array_unshift($templates, 'archive-'.get_post_type().'.twig');
36
+ }
37
+
38
+ $data['posts'] = Timber::get_posts();
39
+
40
+ Timber::render($templates, $data);
timber-starter-theme/timber-starter-theme/author.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The template for displaying Author Archive pages
4
+ *
5
+ * Methods for TimberHelper can be found in the /functions sub-directory
6
+ *
7
+ * @package WordPress
8
+ * @subpackage Timber
9
+ * @since Timber 0.1
10
+ */
11
+ global $wp_query;
12
+
13
+ $data = Timber::get_context();
14
+ $data['posts'] = Timber::get_posts();
15
+ if (isset($wp_query->query_vars['author'])){
16
+ $author = new TimberUser($wp_query->query_vars['author']);
17
+ $data['author'] = $author;
18
+ $data['title'] = 'Author Archives: ' . $author->name();
19
+ }
20
+ Timber::render(array('author.twig', 'archive.twig'), $data);
timber-starter-theme/timber-starter-theme/footer.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Third party plugins that hijack the theme will call wp_footer() to get the footer template.
4
+ * We use this to end our output buffer (started in header.php) and render into the view/page-plugin.twig template.
5
+ */
6
+ $timberContext = $GLOBALS['timberContext'];
7
+ if (!isset($timberContext)) {
8
+ throw new \Exception('Timber context not set in footer.');
9
+ }
10
+ $timberContext['content'] = ob_get_contents();
11
+ ob_end_clean();
12
+ $templates = array('page-plugin.twig');
13
+ Timber::render($templates, $timberContext);
timber-starter-theme/timber-starter-theme/functions.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!class_exists('Timber')){
4
+ add_action( 'admin_notices', function(){
5
+ echo '<div class="error"><p>Timber not activated. Make sure you activate the plugin in <a href="' . admin_url('plugins.php#timber') . '">' . admin_url('plugins.php') . '</a></p></div>';
6
+ });
7
+ return;
8
+ }
9
+
10
+ class StarterSite extends TimberSite {
11
+
12
+ function __construct(){
13
+ add_theme_support('post-formats');
14
+ add_theme_support('post-thumbnails');
15
+ add_theme_support('menus');
16
+ add_filter('timber_context', array($this, 'add_to_context'));
17
+ add_filter('get_twig', array($this, 'add_to_twig'));
18
+ add_action('init', array($this, 'register_post_types'));
19
+ add_action('init', array($this, 'register_taxonomies'));
20
+ parent::__construct();
21
+ }
22
+
23
+ function register_post_types(){
24
+ //this is where you can register custom post types
25
+ }
26
+
27
+ function register_taxonomies(){
28
+ //this is where you can register custom taxonomies
29
+ }
30
+
31
+ function add_to_context($context){
32
+ $context['foo'] = 'bar';
33
+ $context['stuff'] = 'I am a value set in your functions.php file';
34
+ $context['notes'] = 'These values are available everytime you call Timber::get_context();';
35
+ $context['menu'] = new TimberMenu();
36
+ $context['site'] = $this;
37
+ return $context;
38
+ }
39
+
40
+ function add_to_twig($twig){
41
+ /* this is where you can add your own fuctions to twig */
42
+ $twig->addExtension(new Twig_Extension_StringLoader());
43
+ $twig->addFilter('myfoo', new Twig_Filter_Function('myfoo'));
44
+ return $twig;
45
+ }
46
+
47
+ }
48
+
49
+ new StarterSite();
50
+
51
+ function myfoo($text){
52
+ $text .= ' bar!';
53
+ return $text;
54
+ }
timber-starter-theme/timber-starter-theme/header.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Third party plugins that hijack the theme will call wp_head() to get the header template.
4
+ * We use this to start our output buffer and render into the view/page-plugin.twig template in footer.php
5
+ */
6
+ $GLOBALS['timberContext'] = Timber::get_context();
7
+ ob_start();
timber-starter-theme/timber-starter-theme/index.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The main template file
4
+ * This is the most generic template file in a WordPress theme
5
+ * and one of the two required files for a theme (the other being style.css).
6
+ * It is used to display a page when nothing more specific matches a query.
7
+ * E.g., it puts together the home page when no home.php file exists
8
+ *
9
+ * Methods for TimberHelper can be found in the /functions sub-directory
10
+ *
11
+ * @package WordPress
12
+ * @subpackage Timber
13
+ * @since Timber 0.1
14
+ */
15
+
16
+ if (!class_exists('Timber')){
17
+ echo 'Timber not activated. Make sure you activate the plugin in <a href="/wp-admin/plugins.php#timber">/wp-admin/plugins.php</a>';
18
+ return;
19
+ }
20
+ $context = Timber::get_context();
21
+ $context['posts'] = Timber::get_posts();
22
+ $context['foo'] = 'bar';
23
+ $templates = array('index.twig');
24
+ if (is_home()){
25
+ array_unshift($templates, 'home.twig');
26
+ }
27
+ Timber::render($templates, $context);
28
+
29
+
timber-starter-theme/timber-starter-theme/js/site.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ jQuery(document).ready(function($) {
2
+
3
+ // Your JavaScript goes here
4
+
5
+ });
timber-starter-theme/timber-starter-theme/page.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The template for displaying all pages.
4
+ *
5
+ * This is the template that displays all pages by default.
6
+ * Please note that this is the WordPress construct of pages
7
+ * and that other 'pages' on your WordPress site will use a
8
+ * different template.
9
+ *
10
+ * To generate specific templates for your pages you can use:
11
+ * /mytheme/views/page-mypage.twig
12
+ * (which will still route through this PHP file)
13
+ * OR
14
+ * /mytheme/page-mypage.php
15
+ * (in which case you'll want to duplicate this file and save to the above path)
16
+ *
17
+ * Methods for TimberHelper can be found in the /functions sub-directory
18
+ *
19
+ * @package WordPress
20
+ * @subpackage Timber
21
+ * @since Timber 0.1
22
+ */
23
+
24
+ $context = Timber::get_context();
25
+ $post = new TimberPost();
26
+ $context['post'] = $post;
27
+ Timber::render(array('page-' . $post->post_name . '.twig', 'page.twig'), $context);
timber-starter-theme/timber-starter-theme/screenshot.png ADDED
Binary file
timber-starter-theme/timber-starter-theme/search.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Search results page
4
+ *
5
+ * Methods for TimberHelper can be found in the /functions sub-directory
6
+ *
7
+ * @package WordPress
8
+ * @subpackage Timber
9
+ * @since Timber 0.1
10
+ */
11
+
12
+
13
+ $templates = array('search.twig', 'archive.twig', 'index.twig');
14
+ $context = Timber::get_context();
15
+
16
+ $context['title'] = 'Search results for '. get_search_query();
17
+ $context['posts'] = Timber::get_posts();
18
+
19
+ Timber::render($templates, $context);
timber-starter-theme/timber-starter-theme/sidebar.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Template for displaying all single posts
4
+ *
5
+ *
6
+ * @package WordPress
7
+ * @subpackage Timber
8
+ */
9
+
10
+ Timber::render(array('sidebar.twig'), $data);
timber-starter-theme/timber-starter-theme/single.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Template for displaying all single posts
4
+ *
5
+ * Methods for TimberHelper can be found in the /functions sub-directory
6
+ *
7
+ * @package WordPress
8
+ * @subpackage Timber
9
+ * @since Timber 0.1
10
+ */
11
+
12
+ $context = Timber::get_context();
13
+ $post = Timber::query_post();
14
+ $context['post'] = $post;
15
+ $context['wp_title'] .= ' - ' . $post->title();
16
+ $context['comment_form'] = TimberHelper::get_comment_form();
17
+
18
+ if (post_password_required($post->ID)){
19
+ Timber::render('single-password.twig', $context);
20
+ } else {
21
+ Timber::render(array('single-' . $post->ID . '.twig', 'single-' . $post->post_type . '.twig', 'single.twig'), $context);
22
+ }
23
+
24
+
timber-starter-theme/timber-starter-theme/style.css ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ /* Theme Name: My Timber Starter Theme
2
+ Description: Starter Theme to use with Timber
3
+ Author: Upstatement and YOU!
4
+ */
timber-starter-theme/timber-starter-theme/views/404.twig ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+
3
+ {% block content %}
4
+ Sorry, we couldn't find what you're looking for.
5
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/author.twig ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+ {% block content %}
3
+
4
+ {% for post in posts %}
5
+ {% include ["tease-"~post.post_type~".twig", "tease.twig"] %}
6
+ {% endfor %}
7
+
8
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/base.twig ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% block html_head_container %}
2
+ {% include 'html-header.twig' %}
3
+ {% block head %}
4
+ {% endblock %}
5
+ </head>
6
+ {% endblock %}
7
+ <body class="{{body_class}}" data-template="base.twig">
8
+ <header class="header" >
9
+ {% block header %}
10
+ <div class="wrapper">
11
+
12
+ <h1 class="hdr-logo" role="banner">
13
+ <a class="hdr-logo-link" href="/" title="Timber" rel="home">{{site.name}}</a>
14
+ </h1>
15
+ <nav id="access" class="main-navigation" role="navigation">
16
+ <ul>
17
+ {% for item in menu.items %}
18
+ <li id="menu-item-{{item.ID}}" class="menu-item menu-item-type-{{item.type}} menu-item-object-{{item.object}} menu-item-{{item.ID}}">
19
+ <a href="{{item.link}}">{{item.title}}</a>
20
+ </li>
21
+ {% endfor %}
22
+ </ul>
23
+ </nav><!-- #access -->
24
+
25
+ </div>
26
+ {% endblock %}
27
+ </header>
28
+
29
+
30
+ <section id="content" role="main" class="content-wrapper">
31
+ {% if title %}<h1>{{title}}</h1>{% endif %}
32
+ <div class="wrapper {{sidebar_class}}">
33
+ {% block content %}
34
+ Sorry, no content
35
+ {% endblock %}
36
+ </div>
37
+ {% if sidebar %}
38
+ <aside class="layout-sidebar">
39
+ {{sidebar}}
40
+ </aside>
41
+ {% endif %}
42
+ </section>
43
+
44
+ {% block footer %}
45
+ <footer id="footer">
46
+ {% include 'footer.twig' %}
47
+ </footer>
48
+ {{ function('wp_footer') }}
49
+ {% endblock %}
50
+ </body>
51
+ </html>
timber-starter-theme/timber-starter-theme/views/comment.twig ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <div class="blog-comment {{comment.comment_type}}" id="blog-comment-{{comment.ID}}">
2
+ <h5 class="comment-author">{{comment.author.name}} says</h5>
3
+ <div class="comment-content">{{comment.comment_content|wpautop}}</div>
4
+ </div>
timber-starter-theme/timber-starter-theme/views/footer.twig ADDED
@@ -0,0 +1 @@
 
1
+ Copyright {{"now"|date('Y')}}
timber-starter-theme/timber-starter-theme/views/html-header.twig ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <!--[if lt IE 7]><html class="no-js ie ie6 lt-ie9 lt-ie8 lt-ie7" {{site.language_attributes}}> <![endif]-->
3
+ <!--[if IE 7]><html class="no-js ie ie7 lt-ie9 lt-ie8" {{site.language_attributes}}> <![endif]-->
4
+ <!--[if IE 8]><html class="no-js ie ie8 lt-ie9" {{site.language_attributes}}> <![endif]-->
5
+ <!--[if gt IE 8]><!--><html class="no-js" {{site.language_attributes}}> <!--<![endif]-->
6
+ <head>
7
+ <meta charset="{{site.charset}}" />
8
+ <title>{{wp_title}}</title>
9
+ <meta name="description" content="{{site.description}}">
10
+ <link rel="stylesheet" href="{{site.theme.link}}/style.css" type="text/css" media="screen" />
11
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
12
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
13
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
+ <link rel="pingback" href="{{site.pingback_url}}" />
15
+ {{function('wp_head')}}
timber-starter-theme/timber-starter-theme/views/index.twig ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+
3
+ {% block content %}
4
+ <h2>{{foo}}</h2>
5
+ <p>{{qux}}</p>
6
+ {% for post in posts %}
7
+ {% include ['tease-'~post.post_type~'.twig', 'tease.twig'] %}
8
+ {% endfor %}
9
+
10
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/page-plugin.twig ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+
3
+ {% block content %}
4
+ <div class="container content-wrapper">
5
+ {{content}}
6
+ </div> <!-- /content-wrapper -->
7
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/page.twig ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+
3
+ {% block content %}
4
+
5
+ <div class="content-wrapper">
6
+ <article class="post-type-{{post.post_type}}" id="post-{{post.ID}}">
7
+ <section class="article-content">
8
+ <h1 class="article-h1">{{post.title}}</h1>
9
+
10
+ <div class="article-body">
11
+ {{post.content}}
12
+ </div>
13
+ </section>
14
+
15
+ </article>
16
+ </div> <!-- /content-wrapper -->
17
+
18
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/sidebar.twig ADDED
@@ -0,0 +1 @@
 
1
+ Sidebar in Timber. Add HTML to your hearts content.
timber-starter-theme/timber-starter-theme/views/single-password.twig ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+ {% block content %}
3
+ <form class="password-form" action="/wp-login.php?action=postpass" method="post">
4
+ <label for="pwbox-{{post.ID}}">Password:</label>
5
+ <input class="password-box" name="post_password" id="pwbox-{{post.ID}}" type="password" placeholder="Password" size="20" maxlength="20" />
6
+ <input class="password-btn" type="submit" name="Submit" value="Submit" />
7
+ </form>
8
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/single.twig ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "base.twig" %}
2
+
3
+ {% block content %}
4
+
5
+ <div class="content-wrapper">
6
+ <article class="post-type-{{post.post_type}}" id="post-{{post.ID}}">
7
+ <section class="article-content">
8
+ <h1 class="article-h1">{{post.title}}</h1>
9
+
10
+ <p class="blog-author">
11
+ <span>By</span><a href="{{post.author.path}}"> {{ post.author.name }} </a><span>&bull;</span> {{ post.post_date|date}}
12
+ </p>
13
+
14
+ <div class="article-body">
15
+ {{post.content}}
16
+ </div>
17
+ </section>
18
+
19
+ <section class="comments">
20
+ <div class="respond">
21
+ <h3 class="h2">Comments</h3>
22
+ {{ comment_form }}
23
+ </div>
24
+ <div class="responses">
25
+ {% for cmt in post.get_comments() %}
26
+ {% include "comment.twig" with {comment:cmt} %}
27
+ {% endfor %}
28
+ </div>
29
+
30
+ </section>
31
+
32
+ </article>
33
+ </div> <!-- /content-wrapper -->
34
+
35
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/tease-post.twig ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ {% extends "tease.twig" %}
2
+ {% block content %}
3
+ <h2 class="h2"><a href="{{post.link}}">{{post.title}}</a></h2>
4
+ <p>{{post.get_preview(25)}}</p>
5
+
6
+ {% if post.thumbnail.src %}
7
+ <img src="{{post.thumbnail.src}}" />
8
+ {% endif %}
9
+ {% endblock %}
timber-starter-theme/timber-starter-theme/views/tease.twig ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <article class="tease tease-{{post.post_type}}" id="tease-{{post.ID}}">
2
+ {% block content %}
3
+ <h2 class="h2"><a href="{{post.link}}">{{post.title}}</a></h2>
4
+ <p>{{post.get_preview}}</p>
5
+
6
+ {% if post.get_thumbnail %}
7
+ <img src="{{post.thumbnail.src}}" />
8
+ {% endif %}
9
+ {% endblock %}
10
+ </article>
timber-starter-theme/views/single.twig CHANGED
@@ -19,14 +19,13 @@
19
  <section class="comments">
20
  <div class="respond">
21
  <h3 class="h2">Comments</h3>
22
- {{ comment_form }}
23
- </div>
24
- <div class="responses">
25
-
26
- {% for cmt in post.get_comments() %}
27
- {% include "comment.twig" with {comment:cmt} %}
28
- {% endfor %}
29
- </div>
30
 
31
  </section>
32
 
19
  <section class="comments">
20
  <div class="respond">
21
  <h3 class="h2">Comments</h3>
22
+ {{ comment_form }}
23
+ </div>
24
+ <div class="responses">
25
+ {% for cmt in post.get_comments() %}
26
+ {% include "comment.twig" with {comment:cmt} %}
27
+ {% endfor %}
28
+ </div>
 
29
 
30
  </section>
31
 
timber.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Timber
4
  Plugin URI: http://timber.upstatement.com
5
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates
6
  Author: Jared Novack + Upstatement
7
- Version: 0.20.6
8
  Author URI: http://upstatement.com/
9
  */
10
 
@@ -87,8 +87,8 @@ class Timber {
87
  }
88
  }
89
 
90
- protected function init_constants() {
91
- define("TIMBER_LOC", realpath(__DIR__));
92
  }
93
 
94
  /* Post Retrieval
@@ -181,7 +181,7 @@ class Timber {
181
  /**
182
  * @param array $results
183
  * @param string $PostClass
184
- * @return array
185
  * @deprecated since 0.20.0
186
  */
187
  static function handle_post_results($results, $PostClass = 'TimberPost') {
@@ -309,7 +309,7 @@ class Timber {
309
  }
310
 
311
  /**
312
- * @param array $string a string with twig variables
313
  * @param array $data an array with data in it
314
  * @return bool|string
315
  */
@@ -343,7 +343,7 @@ class Timber {
343
  }
344
 
345
  /**
346
- * @param array $string a string with twig variables
347
  * @param array $data an array with data in it
348
  * @return bool|string
349
  */
@@ -514,6 +514,9 @@ class Timber {
514
  return str_replace(ABSPATH, '', realpath($dir));
515
  }
516
 
 
 
 
517
  public static function get_calling_script_dir($offset = 0) {
518
  $caller = self::get_calling_script_file($offset);
519
  if (!is_null($caller)){
4
  Plugin URI: http://timber.upstatement.com
5
  Description: The WordPress Timber Library allows you to write themes using the power Twig templates
6
  Author: Jared Novack + Upstatement
7
+ Version: 0.20.7
8
  Author URI: http://upstatement.com/
9
  */
10
 
87
  }
88
  }
89
 
90
+ function init_constants() {
91
+ defined("TIMBER_LOC") or define("TIMBER_LOC", realpath(__DIR__));
92
  }
93
 
94
  /* Post Retrieval
181
  /**
182
  * @param array $results
183
  * @param string $PostClass
184
+ * @return TimberPostsCollection
185
  * @deprecated since 0.20.0
186
  */
187
  static function handle_post_results($results, $PostClass = 'TimberPost') {
309
  }
310
 
311
  /**
312
+ * @param string $string a string with twig variables
313
  * @param array $data an array with data in it
314
  * @return bool|string
315
  */
343
  }
344
 
345
  /**
346
+ * @param string $string a string with twig variables
347
  * @param array $data an array with data in it
348
  * @return bool|string
349
  */
514
  return str_replace(ABSPATH, '', realpath($dir));
515
  }
516
 
517
+ /**
518
+ * @return boolean|string
519
+ */
520
  public static function get_calling_script_dir($offset = 0) {
521
  $caller = self::get_calling_script_file($offset);
522
  if (!is_null($caller)){
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit9e7b538325e8f0567809c5446a15052f::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit36822b6ae1dbe3e7b97c1dd14c0cb078::getLoader();
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit9e7b538325e8f0567809c5446a15052f
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit9e7b538325e8f0567809c5446a15052f
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit9e7b538325e8f0567809c5446a15052f', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit9e7b538325e8f0567809c5446a15052f', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(__DIR__);
27
  $baseDir = dirname($vendorDir);
@@ -47,7 +47,7 @@ class ComposerAutoloaderInit9e7b538325e8f0567809c5446a15052f
47
  }
48
  }
49
 
50
- function composerRequire9e7b538325e8f0567809c5446a15052f($file)
51
  {
52
  require $file;
53
  }
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit36822b6ae1dbe3e7b97c1dd14c0cb078
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit36822b6ae1dbe3e7b97c1dd14c0cb078', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit36822b6ae1dbe3e7b97c1dd14c0cb078', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(__DIR__);
27
  $baseDir = dirname($vendorDir);
47
  }
48
  }
49
 
50
+ function composerRequire36822b6ae1dbe3e7b97c1dd14c0cb078($file)
51
  {
52
  require $file;
53
  }
vendor/vendor/asm89/twig-cache-extension/.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ phpunit.xml
2
+ composer.lock
3
+ composer.phar
4
+ /vendor/
vendor/vendor/asm89/twig-cache-extension/.travis.yml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.3
5
+ - 5.4
6
+ - 5.5
7
+
8
+ matrix:
9
+ allow_failures:
10
+ - php: 5.5
11
+
12
+ before_script: composer install --dev
13
+
14
+ script: phpunit
vendor/vendor/asm89/twig-cache-extension/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2013 Alexander <iam.asm89@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
vendor/vendor/asm89/twig-cache-extension/README.md ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig cache extension
2
+ ====================
3
+
4
+ The missing cache extension for Twig. The extension allows for caching rendered parts of
5
+ templates using several cache strategies.
6
+
7
+ [![Build Status](https://secure.travis-ci.org/asm89/twig-cache-extension.png?branch=master)](http://travis-ci.org/asm89/twig-cache-extension)
8
+
9
+ ## Installation
10
+
11
+ The extension is installable via composer:
12
+
13
+ ```js
14
+ {
15
+ "require": {
16
+ "asm89/twig-cache-extension": "*"
17
+ }
18
+ }
19
+ ```
20
+
21
+ ## Quick start
22
+
23
+ ### Setup
24
+
25
+ A minimal setup for adding the extension with the `LifeTimeCacheStrategy` and
26
+ doctrine array cache is as following:
27
+
28
+ ```php
29
+ <?php
30
+
31
+ use Doctrine\Common\Cache\ArrayCache;
32
+ use Asm89\Twig\CacheExtension\CacheProvider\DoctrineCacheAdapter;
33
+ use Asm89\Twig\CacheExtension\CacheStrategy\LifetimeCacheStrategy;
34
+ use Asm89\Twig\CacheExtension\Extension as CacheExtension;
35
+
36
+ $cacheProvider = new DoctrineCacheAdapter(new ArrayCache());
37
+ $cacheStrategy = new LifetimeCacheStrategy($cacheProvider);
38
+ $cacheExtension = new CacheExtension($cacheStrategy);
39
+
40
+ $twig->addExtension($cacheExtension);
41
+ ```
42
+
43
+ ### Usage
44
+
45
+ To cache a part of a template in Twig surround the code with a `cache` block.
46
+ The cache block takes two parameters, first an "annotation" part, second the
47
+ "value" the cache strategy can work with. Example:
48
+
49
+ ```jinja
50
+ {% cache 'v1/summary' 900 %}
51
+ {# heavy lifting template stuff here, include/render other partials etc #}
52
+ {% endcache %}
53
+ ```
54
+
55
+ Cache blocks can be nested:
56
+
57
+ ```jinja
58
+ {% cache 'v1' 900 %}
59
+ {% for item in items %}
60
+ {% cache 'v1' item %}
61
+ {# ... #}
62
+ {% endcache %}
63
+ {% endfor %}
64
+ {% endcache %}
65
+
66
+ ```
67
+
68
+ ## Cache strategies
69
+
70
+ The extension ships with a few cache strategies out of the box. Setup and usage
71
+ of all of them is described below.
72
+
73
+ ### Lifetime
74
+
75
+ See the "Quick start" for usage information of the `LifetimeCacheStrategy`.
76
+
77
+ ### Generational
78
+
79
+ Strategy for generational caching.
80
+
81
+ In theory the strategy only saves fragments to the cache with infinite
82
+ lifetime. The key of the strategy lies in the fact that the keys for blocks
83
+ will change as the value for which the key is generated changes.
84
+
85
+ For example: entities containing a last update time, would include a timestamp
86
+ in the key. For an interesting blog post about this type of caching see:
87
+ http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works
88
+
89
+ #### Setup
90
+
91
+ In order to use the strategy you need to setup a `KeyGenerator` class that is
92
+ able to generate a cache key for a given value.
93
+
94
+ The following naive example always assumes the value is an object with the methods
95
+ `getId()` and `getUpdatedAt()` method. The key then composed from the class
96
+ name, the id and the updated time of the object:
97
+
98
+ ```php
99
+ <?php
100
+
101
+ use Asm89\Twig\CacheExtension\CacheStrategy\KeyGeneratorInterface;
102
+
103
+ class MyKeyGenerator implements KeyGeneratorInterface
104
+ {
105
+ public function generateKey($value)
106
+ {
107
+ return get_class($value) . '_' . $value->getId() . '_' . $value->getUpdatedAt();
108
+ }
109
+
110
+ }
111
+ ```
112
+
113
+ Next the `GenerationalCacheStrategy` needs to be setup with the keygenerator.
114
+
115
+ ```php
116
+ <?php
117
+
118
+ use Asm89\Twig\CacheExtension\CacheStrategy\GenerationalCacheStrategy;
119
+ use Asm89\Twig\CacheExtension\Extension as CacheExtension;
120
+
121
+ $keyGenerator = new MyKeyGenerator();
122
+ $cacheProvider = /* see Quick start */;
123
+ $cacheStrategy = new GenerationalCacheStrategy($cacheProvider, $keyGenerator, 0 /* = infinite lifetime */);
124
+ $cacheExtension = new CacheExtension($cacheStrategy);
125
+
126
+ $twig->addExtension($cacheExtension);
127
+ ```
128
+
129
+ #### Usage
130
+
131
+ The strategy expects an object as value for determining the cache key of the
132
+ block:
133
+
134
+ ```jinja
135
+ {% cache 'v1/summary' item %}
136
+ {# heavy lifting template stuff here, include/render other partials etc #}
137
+ {% endcache %}
138
+ ```
139
+
140
+ ### Using multiple strategies
141
+
142
+ Different cache strategies are useful for different usecases. It is possible to
143
+ mix multiple strategies in an application with the
144
+ `IndexedChainingCacheStrategy`. The strategy takes an array of `'name' =>
145
+ $strategy` and delegates the caching to the appropriate strategy.
146
+
147
+ #### Setup
148
+
149
+ ```php
150
+ <?php
151
+
152
+ use Asm89\Twig\CacheExtension\CacheStrategy\IndexedChainingCacheStrategy;
153
+ use Asm89\Twig\CacheExtension\Extension as CacheExtension;
154
+
155
+ $cacheStrategy = new IndexedChainingCacheStrategy(array(
156
+ 'time' => $lifetimeCacheStrategy,
157
+ 'gen' => $generationalCacheStrategy,
158
+ ));
159
+ $cacheExtension = new CacheExtension($cacheStrategy);
160
+
161
+ $twig->addExtension($cacheExtension);
162
+ ```
163
+
164
+ #### Usage
165
+
166
+ The strategy expects an array with as key the name of the strategy which it
167
+ needs to delegate to and as value the appropriate value for the delegated
168
+ strategy.
169
+
170
+ ```jinja
171
+ {# delegate to lifetime strategy #}
172
+ {% cache 'v1/summary' {time: 300} %}
173
+ {# heavy lifting template stuff here, include/render other partials etc #}
174
+ {% endcache %}
175
+
176
+ {# delegate to generational strategy #}
177
+ {% cache 'v1/summary' {gen: item} %}
178
+ {# heavy lifting template stuff here, include/render other partials etc #}
179
+ {% endcache %}
180
+ ```
181
+
182
+ ## Implementing a cache strategy
183
+
184
+ Creating separate caches for different access levels, languages or other
185
+ usecases can be done by implementing a custom cache strategy. In order to do so
186
+ implement the `CacheProviderInterface`. It is recommended to use composition
187
+ and wrap a custom strategy around an existing one.
188
+
189
+ ## Authors
190
+
191
+ Alexander <iam.asm89@gmail.com>
192
+
193
+ ## License
194
+
195
+ twig-cache-extension is licensed under the MIT License - see the LICENSE file for details
vendor/vendor/asm89/twig-cache-extension/composer.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "asm89/twig-cache-extension",
3
+ "description": "Caching template fragments with Twig.",
4
+ "keywords": ["twig", "cache", "extension"],
5
+ "homepage": "https://github.com/asm89/twig-cache-extension",
6
+ "type": "library",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Alexander",
11
+ "email": "iam.asm89@gmail.com"
12
+ }
13
+ ],
14
+ "require": {
15
+ "php": ">=5.3.2",
16
+ "twig/twig": "1.*"
17
+ },
18
+ "require-dev": {
19
+ "doctrine/cache": "1.*"
20
+ },
21
+ "autoload": {
22
+ "psr-0": { "Asm89\\Twig\\CacheExtension\\": "lib/" }
23
+ },
24
+ "extra": {
25
+ "branch-alias": {
26
+ "dev-master": "0.1-dev"
27
+ }
28
+ }
29
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheProvider/DoctrineCacheAdapter.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\CacheProvider;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheProviderInterface;
15
+ use Doctrine\Common\Cache\Cache;
16
+
17
+ /**
18
+ * Adapter class to use the cache classes provider by Doctrine.
19
+ *
20
+ * @author Alexander <iam.asm89@gmail.com>
21
+ */
22
+ class DoctrineCacheAdapter implements CacheProviderInterface
23
+ {
24
+ private $cache;
25
+
26
+ /**
27
+ * @param Cache $cache
28
+ */
29
+ public function __construct(Cache $cache)
30
+ {
31
+ $this->cache = $cache;
32
+ }
33
+
34
+ /**
35
+ * {@inheritDoc}
36
+ */
37
+ public function fetch($key)
38
+ {
39
+ return $this->cache->fetch($key);
40
+ }
41
+
42
+ /**
43
+ * {@inheritDoc}
44
+ */
45
+ public function save($key, $value, $lifetime = 0)
46
+ {
47
+ return $this->cache->save($key, $value, $lifetime);
48
+ }
49
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheProviderInterface.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension;
13
+
14
+ /**
15
+ * Cache provider interface.
16
+ *
17
+ * @author Alexander <iam.asm89@gmail.com>
18
+ */
19
+ interface CacheProviderInterface
20
+ {
21
+ /**
22
+ * @param string $key
23
+ *
24
+ * @return mixed False, if there was no value to be fetched. Null or a string otherwise.
25
+ */
26
+ public function fetch($key);
27
+
28
+ /**
29
+ * @param string $key
30
+ * @param string $value
31
+ * @param integer $lifetime
32
+ */
33
+ public function save($key, $value, $lifetime = 0);
34
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/GenerationalCacheStrategy.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\CacheStrategy;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheProviderInterface;
15
+ use Asm89\Twig\CacheExtension\CacheStrategyInterface;
16
+
17
+ /**
18
+ * Strategy for generational caching.
19
+ *
20
+ * In theory the strategy only saves fragments to the cache with infinite
21
+ * lifetime. The key of the strategy lies in the fact that the keys for blocks
22
+ * will change as the value for which the key is generated changes.
23
+ *
24
+ * For example: entities containing a last update time, would include a
25
+ * timestamp in the key.
26
+ *
27
+ * @see http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works
28
+ *
29
+ * @author Alexander <iam.asm89@gmail.com>
30
+ */
31
+ class GenerationalCacheStrategy implements CacheStrategyInterface
32
+ {
33
+ private $keyGenerator;
34
+ private $cache;
35
+ private $lifetime;
36
+
37
+ /**
38
+ * @param CacheProviderInterface $cache
39
+ * @param KeyGeneratorInterface $keyGenerator
40
+ * @param integer $lifetime
41
+ */
42
+ public function __construct(CacheProviderInterface $cache, KeyGeneratorInterface $keyGenerator, $lifetime = 0)
43
+ {
44
+ $this->keyGenerator = $keyGenerator;
45
+ $this->cache = $cache;
46
+ $this->lifetime = $lifetime;
47
+ }
48
+
49
+ /**
50
+ * {@inheritDoc}
51
+ */
52
+ public function fetchBlock($key)
53
+ {
54
+ return $this->cache->fetch($key);
55
+ }
56
+
57
+ /**
58
+ * {@inheritDoc}
59
+ */
60
+ public function generateKey($annotation, $value)
61
+ {
62
+ $key = $this->keyGenerator->generateKey($value);
63
+
64
+ if (null === $key) {
65
+ // todo: more specific exception
66
+ throw new \RuntimeException('Key generator did not return a key.');
67
+ }
68
+
69
+ return $annotation . '__GCS__' . $key;
70
+ }
71
+
72
+ /**
73
+ * {@inheritDoc}
74
+ */
75
+ public function saveBlock($key, $block)
76
+ {
77
+ return $this->cache->save($key, $block, $this->lifetime);
78
+ }
79
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/IndexedChainingCacheStrategy.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\CacheStrategy;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheStrategyInterface;
15
+
16
+ /**
17
+ * Combines several configured cache strategies.
18
+ *
19
+ * Useful for combining for example generational cache strategy with a lifetime
20
+ * cache strategy, but also useful when combining several generational cache
21
+ * strategies which differ on cache lifetime (infinite, 1hr, 5m).
22
+ *
23
+ * @author Alexander <iam.asm89@gmail.com>
24
+ */
25
+ class IndexedChainingCacheStrategy implements CacheStrategyInterface
26
+ {
27
+ private $strategies;
28
+
29
+ /**
30
+ * @param array $strategies
31
+ */
32
+ public function __construct(array $strategies)
33
+ {
34
+ $this->strategies = $strategies;
35
+ }
36
+
37
+ /**
38
+ * {@inheritDoc}
39
+ */
40
+ public function fetchBlock($key)
41
+ {
42
+ return $this->strategies[$key['strategyKey']]->fetchBlock($key['key']);
43
+ }
44
+
45
+ /**
46
+ * {@inheritDoc}
47
+ */
48
+ public function generateKey($annotation, $value)
49
+ {
50
+ if (! is_array($value) || null === $strategyKey = key($value)) {
51
+ //todo: specialized exception
52
+ throw new \RuntimeException('No strategy key found in value.');
53
+ }
54
+
55
+ if (! isset($this->strategies[$strategyKey])) {
56
+ //todo: specialized exception
57
+ throw new \RuntimeException(sprintf('No strategy configured with key "%s".', $strategyKey));
58
+ }
59
+
60
+ $key = $this->strategies[$strategyKey]->generateKey($annotation, current($value));
61
+
62
+ return array(
63
+ 'strategyKey' => $strategyKey,
64
+ 'key' => $key,
65
+ );
66
+ }
67
+
68
+ /**
69
+ * {@inheritDoc}
70
+ */
71
+ public function saveBlock($key, $block)
72
+ {
73
+ return $this->strategies[$key['strategyKey']]->saveBlock($key['key'], $block);
74
+ }
75
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/KeyGeneratorInterface.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\CacheStrategy;
13
+
14
+ /**
15
+ * Generates a key for a given value.
16
+ *
17
+ * @author Alexander <iam.asm89@gmail.com>
18
+ */
19
+ interface KeyGeneratorInterface
20
+ {
21
+ /**
22
+ * Generate a cache key for a given value.
23
+ *
24
+ * @param mixed $value
25
+ *
26
+ * @return string
27
+ */
28
+ public function generateKey($value);
29
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategy/LifetimeCacheStrategy.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\CacheStrategy;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheProviderInterface;
15
+ use Asm89\Twig\CacheExtension\CacheStrategyInterface;
16
+
17
+ /**
18
+ * Strategy for caching with a pre-defined lifetime.
19
+ *
20
+ * The value passed to the strategy is the lifetime of the cache block in
21
+ * seconds.
22
+ *
23
+ * @author Alexander <iam.asm89@gmail.com>
24
+ */
25
+ class LifetimeCacheStrategy implements CacheStrategyInterface
26
+ {
27
+ private $cache;
28
+
29
+ /**
30
+ * @param CacheProviderInterface $cache
31
+ */
32
+ public function __construct(CacheProviderInterface $cache)
33
+ {
34
+ $this->cache = $cache;
35
+ }
36
+
37
+ /**
38
+ * {@inheritDoc}
39
+ */
40
+ public function fetchBlock($key)
41
+ {
42
+ return $this->cache->fetch($key['key']);
43
+ }
44
+
45
+ /**
46
+ * {@inheritDoc}
47
+ */
48
+ public function generateKey($annotation, $value)
49
+ {
50
+ if (! is_numeric($value)) {
51
+ //todo: specialized exception
52
+ throw new \RuntimeException('Value is not a valid lifetime.');
53
+ }
54
+
55
+ return array(
56
+ 'lifetime' => $value,
57
+ 'key' => '__LCS__' . $annotation,
58
+ );
59
+ }
60
+
61
+ /**
62
+ * {@inheritDoc}
63
+ */
64
+ public function saveBlock($key, $block)
65
+ {
66
+ return $this->cache->save($key['key'], $block, $key['lifetime']);
67
+ }
68
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/CacheStrategyInterface.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension;
13
+
14
+ /**
15
+ * Cache strategy interface.
16
+ *
17
+ * @author Alexander <iam.asm89@gmail.com>
18
+ */
19
+ interface CacheStrategyInterface
20
+ {
21
+ /**
22
+ * Fetch the block for a given key.
23
+ *
24
+ * @param mixed $key
25
+ *
26
+ * @return string
27
+ */
28
+ public function fetchBlock($key);
29
+
30
+ /**
31
+ * Generate a key for the value.
32
+ *
33
+ * @param string $annotation
34
+ * @param mixed $value
35
+ *
36
+ * @return mixed
37
+ */
38
+ public function generateKey($annotation, $value);
39
+
40
+ /**
41
+ * Save the contents of a rendered block.
42
+ *
43
+ * @param mixed $key
44
+ * @param string $block
45
+ */
46
+ public function saveBlock($key, $block);
47
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/Extension.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension;
13
+
14
+ /**
15
+ * Extension for caching template blocks with twig.
16
+ *
17
+ * @author Alexander <iam.asm89@gmail.com>
18
+ */
19
+ class Extension extends \Twig_Extension
20
+ {
21
+ private $cacheStrategy;
22
+
23
+ /**
24
+ * @param CacheStrategyInterface $cacheStrategy
25
+ */
26
+ public function __construct(CacheStrategyInterface $cacheStrategy)
27
+ {
28
+ $this->cacheStrategy = $cacheStrategy;
29
+ }
30
+
31
+ /**
32
+ * @return CacheStrategyInterface
33
+ */
34
+ public function getCacheStrategy()
35
+ {
36
+ return $this->cacheStrategy;
37
+ }
38
+
39
+ /**
40
+ * {@inheritDoc}
41
+ */
42
+ public function getName()
43
+ {
44
+ return 'asm89_cache';
45
+ }
46
+
47
+ /**
48
+ * {@inheritDoc}
49
+ */
50
+ public function getTokenParsers()
51
+ {
52
+ return array(
53
+ new TokenParser\Cache(),
54
+ );
55
+ }
56
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/Node/CacheNode.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\Node;
13
+
14
+ /**
15
+ * Cache twig node.
16
+ *
17
+ * @author Alexander <iam.asm89@gmail.com>
18
+ */
19
+ class CacheNode extends \Twig_Node
20
+ {
21
+ private static $cacheCount = 1;
22
+
23
+ /**
24
+ * @param string $annotation
25
+ * @param \Twig_Node_Expression $keyInfo
26
+ * @param \Twig_NodeInterface $body
27
+ * @param integer $lineno
28
+ * @param string $tag
29
+ */
30
+ public function __construct($annotation, \Twig_Node_Expression $keyInfo, \Twig_NodeInterface $body, $lineno, $tag = null)
31
+ {
32
+ parent::__construct(array('key_info' => $keyInfo, 'body' => $body), array('annotation' => $annotation), $lineno, $tag);
33
+ }
34
+
35
+ /**
36
+ * {@inheritDoc}
37
+ */
38
+ public function compile(\Twig_Compiler $compiler)
39
+ {
40
+ $i = self::$cacheCount++;
41
+
42
+ $compiler
43
+ ->addDebugInfo($this)
44
+ ->write("\$asm89CacheStrategy".$i." = \$this->getEnvironment()->getExtension('asm89_cache')->getCacheStrategy();\n")
45
+ ->write("\$asm89Key".$i." = \$asm89CacheStrategy".$i."->generateKey('".$this->getAttribute('annotation')."', ")
46
+ ->subcompile($this->getNode('key_info'))
47
+ ->write(");\n")
48
+ ->write("\$asm89CacheBody".$i." = \$asm89CacheStrategy".$i."->fetchBlock(\$asm89Key".$i.");\n")
49
+ ->write("if (\$asm89CacheBody".$i." === false) {\n")
50
+ ->indent()
51
+ ->write("ob_start();\n")
52
+ ->indent()
53
+ ->subcompile($this->getNode('body'))
54
+ ->outdent()
55
+ ->write("\n")
56
+ ->write("\$asm89CacheBody".$i." = ob_get_clean();\n")
57
+ ->write("\$asm89CacheStrategy".$i."->saveBlock(\$asm89Key".$i.", \$asm89CacheBody".$i.");\n")
58
+ ->outdent()
59
+ ->write("}\n")
60
+ ->write("echo \$asm89CacheBody".$i.";\n")
61
+ ;
62
+ }
63
+ }
vendor/vendor/asm89/twig-cache-extension/lib/Asm89/Twig/CacheExtension/TokenParser/Cache.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\TokenParser;
13
+
14
+ use \Twig_Token;
15
+
16
+ /**
17
+ * Parser for cache/endcache blocks.
18
+ *
19
+ * @author Alexander <iam.asm89@gmail.com>
20
+ */
21
+ class Cache extends \Twig_TokenParser
22
+ {
23
+ /**
24
+ * @return boolean
25
+ */
26
+ public function decideCacheEnd(Twig_Token $token)
27
+ {
28
+ return $token->test('endcache');
29
+ }
30
+
31
+ /**
32
+ * {@inheritDoc}
33
+ */
34
+ public function getTag()
35
+ {
36
+ return 'cache';
37
+ }
38
+
39
+ /**
40
+ * {@inheritDoc}
41
+ */
42
+ public function parse(Twig_Token $token)
43
+ {
44
+ $lineno = $token->getLine();
45
+ $stream = $this->parser->getStream();
46
+
47
+ $annotation = $stream->expect(Twig_Token::STRING_TYPE)->getValue();
48
+ $key = $this->parser->getExpressionParser()->parseExpression();
49
+
50
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
51
+ $body = $this->parser->subparse(array($this, 'decideCacheEnd'), true);
52
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
53
+
54
+ return new \Asm89\Twig\CacheExtension\Node\CacheNode($annotation, $key, $body, $lineno, $this->getTag());
55
+ }
56
+ }
vendor/vendor/asm89/twig-cache-extension/phpunit.xml.dist ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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="test/bootstrap.php"
13
+ >
14
+ <testsuites>
15
+ <testsuite name="Twig Cache Extension Test Suite">
16
+ <directory>./test/Asm89/</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+
20
+ <filter>
21
+ <whitelist>
22
+ <directory suffix=".php">./lib/</directory>
23
+ </whitelist>
24
+ </filter>
25
+ </phpunit>
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheProvider/DoctrineCacheAdapterTest.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\Tests\CacheProvider;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheProvider\DoctrineCacheAdapter;
15
+
16
+ class DoctrineCacheAdapterTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testFetch()
19
+ {
20
+ $cacheMock = $this->createCacheMock();
21
+ $cacheMock->expects($this->any())
22
+ ->method('fetch')
23
+ ->will($this->returnValue('fromcache'));
24
+
25
+ $cache = new DoctrineCacheAdapter($cacheMock);
26
+
27
+ $this->assertEquals('fromcache', $cache->fetch('test'));
28
+ }
29
+
30
+ public function testSave()
31
+ {
32
+ $cacheMock = $this->createCacheMock();
33
+ $cacheMock->expects($this->once())
34
+ ->method('save')
35
+ ->with('key', 'value', 42);
36
+
37
+ $cache = new DoctrineCacheAdapter($cacheMock);
38
+
39
+ $cache->save('key', 'value', 42);
40
+ }
41
+
42
+ public function createCacheMock()
43
+ {
44
+ return $this->getMock('Doctrine\Common\Cache\Cache');
45
+ }
46
+ }
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheStrategy/GenerationCacheStrategyTest.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\Tests\CacheStrategy;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheStrategy\GenerationalCacheStrategy;
15
+
16
+ class GenerationalCacheStrategyTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ private $keyGeneratorMock;
19
+ private $cacheProviderMock;
20
+
21
+ public function createCacheStrategy($lifetime = 0)
22
+ {
23
+ $this->keyGeneratorMock = $this->createKeyGeneratorMock();
24
+ $this->cacheProviderMock = $this->createCacheProviderMock();
25
+
26
+ return new GenerationalCacheStrategy($this->cacheProviderMock, $this->keyGeneratorMock, $lifetime);
27
+ }
28
+
29
+ public function testGenerateKeyContainsAnnotation()
30
+ {
31
+ $strategy = $this->createCacheStrategy();
32
+ $this->keyGeneratorMock->expects($this->any())
33
+ ->method('generateKey')
34
+ ->will($this->returnValue('foo'));
35
+
36
+ $this->assertEquals('v42__GCS__foo', $strategy->generateKey('v42', 'value'));
37
+ }
38
+
39
+ /**
40
+ * @expectedException RuntimeException
41
+ */
42
+ public function testGenerationKeyThrowsExceptionWhenKeyGeneratorReturnsNull()
43
+ {
44
+ $strategy = $this->createCacheStrategy();
45
+
46
+ $strategy->generateKey('v42', 'value');
47
+ }
48
+
49
+ /**
50
+ * @dataProvider getLifeTimes
51
+ */
52
+ public function testSaveBlockUsesConfiguredLifetime($lifetime)
53
+ {
54
+ $strategy = $this->createCacheStrategy($lifetime);
55
+ $this->cacheProviderMock->expects($this->any())
56
+ ->method('save')
57
+ ->with('key', 'value', $lifetime)
58
+ ->will($this->returnValue('foo'));
59
+
60
+ $strategy->saveBlock('key', 'value');
61
+ }
62
+
63
+ public function getLifetimes()
64
+ {
65
+ return array(
66
+ array(0),
67
+ array(60),
68
+ );
69
+ }
70
+
71
+ public function createKeyGeneratorMock()
72
+ {
73
+ return $this->getMock('Asm89\Twig\CacheExtension\CacheStrategy\KeyGeneratorInterface');
74
+ }
75
+
76
+ public function createCacheProviderMock()
77
+ {
78
+ return $this->getMock('Asm89\Twig\CacheExtension\CacheProviderInterface');
79
+ }
80
+ }
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheStrategy/IndexedChainingCacheStrategyTest.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\Tests\CacheStrategy;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheStrategy\IndexedChainingCacheStrategy;
15
+
16
+ class IndexedChainingCacheStrategyTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ private $cacheStrategyMocks = array();
19
+
20
+ public function createCacheStrategy()
21
+ {
22
+ foreach($this->getStrategies() as $config) {
23
+ list($key, $return) = $config;
24
+
25
+ $cacheStrategyMock = $this->createCacheStrategyMock();
26
+ $cacheStrategyMock->expects($this->any())
27
+ ->method('generateKey')
28
+ ->will($this->returnValue($return));
29
+
30
+ $this->cacheStrategyMocks[$key] = $cacheStrategyMock;
31
+ }
32
+
33
+ return new IndexedChainingCacheStrategy($this->cacheStrategyMocks);
34
+ }
35
+
36
+ /**
37
+ * @dataProvider getStrategies
38
+ */
39
+ public function testGenerateKeyProxiesToAppropriateStrategy($key, $return)
40
+ {
41
+ $strategy = $this->createCacheStrategy();
42
+
43
+ $generatedKey = $strategy->generateKey('v42', array($key => 'proxied_value'));
44
+
45
+ $this->assertEquals($return, $generatedKey['key']);
46
+ $this->assertEquals($key, $generatedKey['strategyKey']);
47
+ }
48
+
49
+ /**
50
+ * @expectedException RuntimeException
51
+ * @expectedExceptionMessage No strategy configured with key "unknown"
52
+ */
53
+ public function testGenerateKeyThrowsExceptionOnUnknownKey()
54
+ {
55
+ $strategy = $this->createCacheStrategy();
56
+
57
+ $strategy->generateKey('v42', array('unknown' => 'proxied_value'));
58
+ }
59
+
60
+ public function getStrategies()
61
+ {
62
+ return array(
63
+ array('foo', 'foo_key'),
64
+ array('bar', 'bar_key'),
65
+ );
66
+ }
67
+
68
+ public function createCacheStrategyMock()
69
+ {
70
+ return $this->getMock('Asm89\Twig\CacheExtension\CacheStrategyInterface');
71
+ }
72
+ }
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/CacheStrategy/LifetimeCacheStrategyTest.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\Tests\CacheStrategy;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheStrategy\LifetimeCacheStrategy;
15
+
16
+ class LifetimeCacheStrategyTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ private $cacheProviderMock;
19
+
20
+ public function createCacheStrategy()
21
+ {
22
+ $this->cacheProviderMock = $this->createCacheProviderMock();
23
+
24
+ return new LifetimeCacheStrategy($this->cacheProviderMock);
25
+ }
26
+
27
+ public function testGenerateKeyUsesGivenLifetime()
28
+ {
29
+ $strategy = $this->createCacheStrategy();
30
+
31
+ $key = $strategy->generateKey('v42', 42);
32
+
33
+ $this->assertEquals(42, $key['lifetime']);
34
+ }
35
+
36
+ public function testGenerateKeyAnnotatesKey()
37
+ {
38
+ $strategy = $this->createCacheStrategy();
39
+
40
+ $key = $strategy->generateKey('the_annotation', 42);
41
+
42
+ $this->assertContains('the_annotation', $key['key']);
43
+ }
44
+
45
+ /**
46
+ * @dataProvider getInvalidLifetimeValues
47
+ * @expectedException RuntimeException
48
+ */
49
+ public function testGenerateKeyThrowsExceptionWhenNoLifetimeProvided($value)
50
+ {
51
+ $strategy = $this->createCacheStrategy();
52
+
53
+ $strategy->generateKey('v42', $value);
54
+ }
55
+
56
+ public function getInvalidLifetimeValues()
57
+ {
58
+ return array(
59
+ array('foo'),
60
+ array(array('foo')),
61
+ );
62
+ }
63
+
64
+ public function createCacheProviderMock()
65
+ {
66
+ return $this->getMock('Asm89\Twig\CacheExtension\CacheProviderInterface');
67
+ }
68
+ }
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/FunctionalExtensionTest.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ namespace Asm89\Twig\CacheExtension\Tests;
13
+
14
+ use Asm89\Twig\CacheExtension\CacheProvider\DoctrineCacheAdapter;
15
+ use Asm89\Twig\CacheExtension\CacheStrategy\KeyGeneratorInterface;
16
+ use Asm89\Twig\CacheExtension\CacheStrategy\GenerationalCacheStrategy;
17
+ use Asm89\Twig\CacheExtension\CacheStrategy\IndexedChainingCacheStrategy;
18
+ use Asm89\Twig\CacheExtension\CacheStrategy\LifetimeCacheStrategy;
19
+ use Asm89\Twig\CacheExtension\Extension;
20
+ use Doctrine\Common\Cache\ArrayCache;
21
+ use Twig_Loader_Filesystem;
22
+ use Twig_Environment;
23
+
24
+ class FunctionalExtensionTest extends \PHPUnit_Framework_TestCase
25
+ {
26
+ private $cache;
27
+
28
+ protected function createCacheProvider()
29
+ {
30
+ $this->cache = new ArrayCache();
31
+
32
+ return new DoctrineCacheAdapter($this->cache);
33
+ }
34
+
35
+ protected function createCacheStrategy($name = null)
36
+ {
37
+ $cacheProvider = $this->createCacheProvider();
38
+ $keyGenerator = $this->createKeyGenerator();
39
+ $lifetime = 0;
40
+
41
+ switch ($name) {
42
+ case 'time':
43
+ return new LifetimeCacheStrategy($cacheProvider);
44
+ case 'indexed':
45
+ return new IndexedChainingCacheStrategy(array(
46
+ 'gcs' => new GenerationalCacheStrategy($cacheProvider, $keyGenerator, $lifetime),
47
+ 'time' => new LifetimeCacheStrategy($cacheProvider),
48
+ ));
49
+ default:
50
+ return new GenerationalCacheStrategy($cacheProvider, $keyGenerator, $lifetime);
51
+ }
52
+ }
53
+
54
+ protected function createKeyGenerator()
55
+ {
56
+ return new KeyGenerator();
57
+ }
58
+
59
+ protected function createTwig($cacheStrategyName = null)
60
+ {
61
+ $loader = new Twig_Loader_Filesystem(__DIR__ . '/fixtures/');
62
+ $twig = new Twig_Environment($loader);
63
+
64
+ $cache = $this->createCacheProvider();
65
+ $cacheExtension = new Extension($this->createCacheStrategy($cacheStrategyName));
66
+
67
+ $twig->addExtension($cacheExtension);
68
+
69
+ return $twig;
70
+ }
71
+
72
+ protected function getValue($value, $updatedAt)
73
+ {
74
+ return new Value($value, $updatedAt);
75
+ }
76
+
77
+ public function testCachesWithSameCacheKey()
78
+ {
79
+ $twig = $this->createTwig();
80
+
81
+ $rendered = $twig->render('gcs_value.twig', array('value' => $this->getValue('asm89', 1)));
82
+ $this->assertEquals('Hello asm89!', $rendered);
83
+
84
+ $rendered2 = $twig->render('gcs_value.twig', array('value' => $this->getValue('fabpot', 1)));
85
+ $this->assertEquals('Hello asm89!', $rendered2);
86
+ }
87
+
88
+ public function testDifferentCacheOnDifferentAnnotation()
89
+ {
90
+ $twig = $this->createTwig();
91
+
92
+ $rendered = $twig->render('gcs_value.twig', array('value' => $this->getValue('asm89', 1)));
93
+ $this->assertEquals('Hello asm89!', $rendered);
94
+
95
+ $rendered2 = $twig->render('gcs_value.twig', array('value' => $this->getValue('fabpot', 1)));
96
+ $this->assertEquals('Hello asm89!', $rendered2);
97
+
98
+ $rendered3 = $twig->render('gcs_value_v2.twig', array('value' => $this->getValue('fabpot', 1)));
99
+ $this->assertEquals('Hello fabpot!', $rendered3);
100
+ }
101
+
102
+ public function testLifetimeCacheStrategy()
103
+ {
104
+ $twig = $this->createTwig('time');
105
+
106
+ $rendered = $twig->render('lcs_value.twig', array('value' => $this->getValue('asm89', 1)));
107
+ $this->assertEquals('Hello asm89!', $rendered);
108
+
109
+ $rendered2 = $twig->render('lcs_value.twig', array('value' => $this->getValue('fabpot', 1)));
110
+ $this->assertEquals('Hello asm89!', $rendered2);
111
+
112
+ $this->cache->flushAll();
113
+
114
+ $rendered3 = $twig->render('lcs_value.twig', array('value' => $this->getValue('fabpot', 1)));
115
+ $this->assertEquals('Hello fabpot!', $rendered3);
116
+ }
117
+
118
+ public function testIndexedChainingStrategy()
119
+ {
120
+ $twig = $this->createTwig('indexed');
121
+
122
+ $rendered = $twig->render('ics_value.twig', array('value' => $this->getValue('asm89', 1)));
123
+ $this->assertEquals('Hello asm89!', $rendered);
124
+
125
+ $rendered2 = $twig->render('ics_value.twig', array('value' => $this->getValue('fabpot', 1)));
126
+ $this->assertEquals('Hello asm89!', $rendered2);
127
+
128
+ $this->cache->flushAll();
129
+
130
+ $rendered3 = $twig->render('ics_value.twig', array('value' => $this->getValue('fabpot', 1)));
131
+ $this->assertEquals('Hello fabpot!', $rendered3);
132
+ }
133
+
134
+ /**
135
+ * @expectedException Twig_Error_Runtime
136
+ * @expectedExceptionMessage An exception has been thrown during the rendering of a template ("No strategy key found in value.") in "ics_no_key.twig" at line 1.
137
+ */
138
+ public function testIndexedChainingStrategyNeedsKey()
139
+ {
140
+ $twig = $this->createTwig('indexed');
141
+
142
+ $rendered = $twig->render('ics_no_key.twig', array('value' => $this->getValue('asm89', 1)));
143
+ }
144
+
145
+ /**
146
+ * @expectedException Twig_Error_Syntax
147
+ * @expectedExceptionMessage Unexpected token "name" of value "annotation" ("string" expected) in "annotation_not_string.twig"
148
+ */
149
+ public function testAnnotationMustBeString()
150
+ {
151
+ $twig = $this->createTwig();
152
+
153
+ $rendered = $twig->render('annotation_not_string.twig', array('value' => $this->getValue('asm89', 1)));
154
+ }
155
+ }
156
+
157
+ class KeyGenerator implements KeyGeneratorInterface
158
+ {
159
+ public function generateKey($value)
160
+ {
161
+ return get_class($value) . '_' . $value->getUpdatedAt();
162
+ }
163
+
164
+ }
165
+
166
+ class Value
167
+ {
168
+ private $updatedAt;
169
+
170
+ public function __construct($value, $updatedAt)
171
+ {
172
+ $this->value = $value;
173
+ $this->updatedAt = $updatedAt;
174
+ }
175
+
176
+ public function getUpdatedAt()
177
+ {
178
+ return $this->updatedAt;
179
+ }
180
+
181
+ public function __toString()
182
+ {
183
+ return $this->value;
184
+ }
185
+ }
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/annotation_not_string.twig ADDED
@@ -0,0 +1,2 @@
 
 
1
+ {% set annotation = 'v1' %}
2
+ {% cache annotation value %}Hello {{ value }}!{% endcache %}
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/gcs_value.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% cache 'v1' value %}Hello {{ value }}!{% endcache %}
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/gcs_value_v2.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% cache 'v2' value %}Hello {{ value }}!{% endcache %}
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/ics_no_key.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% cache 'v1' 10 %}Hello {{ value }}!{% endcache %}
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/ics_value.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% cache 'v1' {time: 10} %}Hello {{ value }}!{% endcache %}
vendor/vendor/asm89/twig-cache-extension/test/Asm89/Twig/CacheExtension/Tests/fixtures/lcs_value.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% cache 'v1' 10 %}Hello {{ value }}!{% endcache %}
vendor/vendor/asm89/twig-cache-extension/test/bootstrap.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of twig-cache-extension.
5
+ *
6
+ * (c) Alexander <iam.asm89@gmail.com>
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
+ if (file_exists($file = __DIR__.'/../vendor/autoload.php')) {
13
+ $autoload = require_once $file;
14
+ } else {
15
+ throw new RuntimeException('Install dependencies to run test suite.');
16
+ }
vendor/vendor/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer' . '/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInit289078358ffed06c21324f80319e78c1::getLoader();
vendor/vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0 class loader
17
+ *
18
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
19
+ *
20
+ * $loader = new \Composer\Autoload\ClassLoader();
21
+ *
22
+ * // register classes with namespaces
23
+ * $loader->add('Symfony\Component', __DIR__.'/component');
24
+ * $loader->add('Symfony', __DIR__.'/framework');
25
+ *
26
+ * // activate the autoloader
27
+ * $loader->register();
28
+ *
29
+ * // to enable searching the include path (eg. for PEAR packages)
30
+ * $loader->setUseIncludePath(true);
31
+ *
32
+ * In this example, if you try to use a class in the Symfony\Component
33
+ * namespace or one of its children (Symfony\Component\Console for instance),
34
+ * the autoloader will first look for the class under the component/
35
+ * directory, and it will then fallback to the framework/ directory if not
36
+ * found before giving up.
37
+ *
38
+ * This class is loosely based on the Symfony UniversalClassLoader.
39
+ *
40
+ * @author Fabien Potencier <fabien@symfony.com>
41
+ * @author Jordi Boggiano <j.boggiano@seld.be>
42
+ */
43
+ class ClassLoader
44
+ {
45
+ // PSR-4
46
+ private $prefixLengthsPsr4 = array();
47
+ private $prefixDirsPsr4 = array();
48
+ private $fallbackDirsPsr4 = array();
49
+
50
+ // PSR-0
51
+ private $prefixesPsr0 = array();
52
+ private $fallbackDirsPsr0 = array();
53
+
54
+ private $useIncludePath = false;
55
+ private $classMap = array();
56
+
57
+ public function getPrefixes()
58
+ {
59
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
60
+ }
61
+
62
+ public function getPrefixesPsr4()
63
+ {
64
+ return $this->prefixDirsPsr4;
65
+ }
66
+
67
+ public function getFallbackDirs()
68
+ {
69
+ return $this->fallbackDirsPsr0;
70
+ }
71
+
72
+ public function getFallbackDirsPsr4()
73
+ {
74
+ return $this->fallbackDirsPsr4;
75
+ }
76
+
77
+ public function getClassMap()
78
+ {
79
+ return $this->classMap;
80
+ }
81
+
82
+ /**
83
+ * @param array $classMap Class to filename map
84
+ */
85
+ public function addClassMap(array $classMap)
86
+ {
87
+ if ($this->classMap) {
88
+ $this->classMap = array_merge($this->classMap, $classMap);
89
+ } else {
90
+ $this->classMap = $classMap;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Registers a set of PSR-0 directories for a given prefix, either
96
+ * appending or prepending to the ones previously set for this prefix.
97
+ *
98
+ * @param string $prefix The prefix
99
+ * @param array|string $paths The PSR-0 root directories
100
+ * @param bool $prepend Whether to prepend the directories
101
+ */
102
+ public function add($prefix, $paths, $prepend = false)
103
+ {
104
+ if (!$prefix) {
105
+ if ($prepend) {
106
+ $this->fallbackDirsPsr0 = array_merge(
107
+ (array) $paths,
108
+ $this->fallbackDirsPsr0
109
+ );
110
+ } else {
111
+ $this->fallbackDirsPsr0 = array_merge(
112
+ $this->fallbackDirsPsr0,
113
+ (array) $paths
114
+ );
115
+ }
116
+
117
+ return;
118
+ }
119
+
120
+ $first = $prefix[0];
121
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
122
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
123
+
124
+ return;
125
+ }
126
+ if ($prepend) {
127
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
128
+ (array) $paths,
129
+ $this->prefixesPsr0[$first][$prefix]
130
+ );
131
+ } else {
132
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
133
+ $this->prefixesPsr0[$first][$prefix],
134
+ (array) $paths
135
+ );
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Registers a set of PSR-4 directories for a given namespace, either
141
+ * appending or prepending to the ones previously set for this namespace.
142
+ *
143
+ * @param string $prefix The prefix/namespace, with trailing '\\'
144
+ * @param array|string $paths The PSR-0 base directories
145
+ * @param bool $prepend Whether to prepend the directories
146
+ */
147
+ public function addPsr4($prefix, $paths, $prepend = false)
148
+ {
149
+ if (!$prefix) {
150
+ // Register directories for the root namespace.
151
+ if ($prepend) {
152
+ $this->fallbackDirsPsr4 = array_merge(
153
+ (array) $paths,
154
+ $this->fallbackDirsPsr4
155
+ );
156
+ } else {
157
+ $this->fallbackDirsPsr4 = array_merge(
158
+ $this->fallbackDirsPsr4,
159
+ (array) $paths
160
+ );
161
+ }
162
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
163
+ // Register directories for a new namespace.
164
+ $length = strlen($prefix);
165
+ if ('\\' !== $prefix[$length - 1]) {
166
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
167
+ }
168
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
169
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
170
+ } elseif ($prepend) {
171
+ // Prepend directories for an already registered namespace.
172
+ $this->prefixDirsPsr4[$prefix] = array_merge(
173
+ (array) $paths,
174
+ $this->prefixDirsPsr4[$prefix]
175
+ );
176
+ } else {
177
+ // Append directories for an already registered namespace.
178
+ $this->prefixDirsPsr4[$prefix] = array_merge(
179
+ $this->prefixDirsPsr4[$prefix],
180
+ (array) $paths
181
+ );
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Registers a set of PSR-0 directories for a given prefix,
187
+ * replacing any others previously set for this prefix.
188
+ *
189
+ * @param string $prefix The prefix
190
+ * @param array|string $paths The PSR-0 base directories
191
+ */
192
+ public function set($prefix, $paths)
193
+ {
194
+ if (!$prefix) {
195
+ $this->fallbackDirsPsr0 = (array) $paths;
196
+ } else {
197
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Registers a set of PSR-4 directories for a given namespace,
203
+ * replacing any others previously set for this namespace.
204
+ *
205
+ * @param string $prefix The prefix/namespace, with trailing '\\'
206
+ * @param array|string $paths The PSR-4 base directories
207
+ */
208
+ public function setPsr4($prefix, $paths) {
209
+ if (!$prefix) {
210
+ $this->fallbackDirsPsr4 = (array) $paths;
211
+ } else {
212
+ $length = strlen($prefix);
213
+ if ('\\' !== $prefix[$length - 1]) {
214
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
215
+ }
216
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
217
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Turns on searching the include path for class files.
223
+ *
224
+ * @param bool $useIncludePath
225
+ */
226
+ public function setUseIncludePath($useIncludePath)
227
+ {
228
+ $this->useIncludePath = $useIncludePath;
229
+ }
230
+
231
+ /**
232
+ * Can be used to check if the autoloader uses the include path to check
233
+ * for classes.
234
+ *
235
+ * @return bool
236
+ */
237
+ public function getUseIncludePath()
238
+ {
239
+ return $this->useIncludePath;
240
+ }
241
+
242
+ /**
243
+ * Registers this instance as an autoloader.
244
+ *
245
+ * @param bool $prepend Whether to prepend the autoloader or not
246
+ */
247
+ public function register($prepend = false)
248
+ {
249
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
250
+ }
251
+
252
+ /**
253
+ * Unregisters this instance as an autoloader.
254
+ */
255
+ public function unregister()
256
+ {
257
+ spl_autoload_unregister(array($this, 'loadClass'));
258
+ }
259
+
260
+ /**
261
+ * Loads the given class or interface.
262
+ *
263
+ * @param string $class The name of the class
264
+ * @return bool|null True if loaded, null otherwise
265
+ */
266
+ public function loadClass($class)
267
+ {
268
+ if ($file = $this->findFile($class)) {
269
+ includeFile($file);
270
+
271
+ return true;
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Finds the path to the file where the class is defined.
277
+ *
278
+ * @param string $class The name of the class
279
+ *
280
+ * @return string|false The path if found, false otherwise
281
+ */
282
+ public function findFile($class)
283
+ {
284
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
285
+ if ('\\' == $class[0]) {
286
+ $class = substr($class, 1);
287
+ }
288
+
289
+ // class map lookup
290
+ if (isset($this->classMap[$class])) {
291
+ return $this->classMap[$class];
292
+ }
293
+
294
+ $file = $this->findFileWithExtension($class, '.php');
295
+
296
+ // Search for Hack files if we are running on HHVM
297
+ if ($file === null && defined('HHVM_VERSION')) {
298
+ $file = $this->findFileWithExtension($class, '.hh');
299
+ }
300
+
301
+ if ($file === null) {
302
+ // Remember that this class does not exist.
303
+ return $this->classMap[$class] = false;
304
+ }
305
+
306
+ return $file;
307
+ }
308
+
309
+ private function findFileWithExtension($class, $ext)
310
+ {
311
+ // PSR-4 lookup
312
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
313
+
314
+ $first = $class[0];
315
+ if (isset($this->prefixLengthsPsr4[$first])) {
316
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
317
+ if (0 === strpos($class, $prefix)) {
318
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
319
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
320
+ return $file;
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+
327
+ // PSR-4 fallback dirs
328
+ foreach ($this->fallbackDirsPsr4 as $dir) {
329
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
330
+ return $file;
331
+ }
332
+ }
333
+
334
+ // PSR-0 lookup
335
+ if (false !== $pos = strrpos($class, '\\')) {
336
+ // namespaced class name
337
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
338
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
339
+ } else {
340
+ // PEAR-like class name
341
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
342
+ }
343
+
344
+ if (isset($this->prefixesPsr0[$first])) {
345
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
346
+ if (0 === strpos($class, $prefix)) {
347
+ foreach ($dirs as $dir) {
348
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
349
+ return $file;
350
+ }
351
+ }
352
+ }
353
+ }
354
+ }
355
+
356
+ // PSR-0 fallback dirs
357
+ foreach ($this->fallbackDirsPsr0 as $dir) {
358
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
359
+ return $file;
360
+ }
361
+ }
362
+
363
+ // PSR-0 include paths.
364
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
365
+ return $file;
366
+ }
367
+ }
368
+ }
369
+
370
+ /**
371
+ * Scope isolated include.
372
+ *
373
+ * Prevents access to $this/self from included files.
374
+ */
375
+ function includeFile($file)
376
+ {
377
+ include $file;
378
+ }
vendor/vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'Twig_' => array($vendorDir . '/twig/twig/lib'),
10
+ 'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
11
+ 'PHPRouter' => array($vendorDir . '/dannyvankooten/php-router/src'),
12
+ 'Composer\\Installers\\' => array($vendorDir . '/composer/installers/src'),
13
+ 'Asm89\\Twig\\CacheExtension\\' => array($vendorDir . '/asm89/twig-cache-extension/lib'),
14
+ );
vendor/vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit289078358ffed06c21324f80319e78c1
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ public static function getLoader()
17
+ {
18
+ if (null !== self::$loader) {
19
+ return self::$loader;
20
+ }
21
+
22
+ spl_autoload_register(array('ComposerAutoloaderInit289078358ffed06c21324f80319e78c1', 'loadClassLoader'), true, true);
23
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit289078358ffed06c21324f80319e78c1', 'loadClassLoader'));
25
+
26
+ $vendorDir = dirname(__DIR__);
27
+ $baseDir = dirname($vendorDir);
28
+
29
+ $map = require __DIR__ . '/autoload_namespaces.php';
30
+ foreach ($map as $namespace => $path) {
31
+ $loader->set($namespace, $path);
32
+ }
33
+
34
+ $map = require __DIR__ . '/autoload_psr4.php';
35
+ foreach ($map as $namespace => $path) {
36
+ $loader->setPsr4($namespace, $path);
37
+ }
38
+
39
+ $classMap = require __DIR__ . '/autoload_classmap.php';
40
+ if ($classMap) {
41
+ $loader->addClassMap($classMap);
42
+ }
43
+
44
+ $loader->register(true);
45
+
46
+ return $loader;
47
+ }
48
+ }
49
+
50
+ function composerRequire289078358ffed06c21324f80319e78c1($file)
51
+ {
52
+ require $file;
53
+ }
vendor/vendor/composer/installed.json ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "composer/installers",
4
+ "version": "v1.0.15",
5
+ "version_normalized": "1.0.15.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/composer/installers.git",
9
+ "reference": "8e6a72a78f6cfd537fde3350720dfdc9ae3c5621"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/composer/installers/zipball/8e6a72a78f6cfd537fde3350720dfdc9ae3c5621",
14
+ "reference": "8e6a72a78f6cfd537fde3350720dfdc9ae3c5621",
15
+ "shasum": ""
16
+ },
17
+ "replace": {
18
+ "roundcube/plugin-installer": "*",
19
+ "shama/baton": "*"
20
+ },
21
+ "require-dev": {
22
+ "composer/composer": "1.0.*@dev",
23
+ "phpunit/phpunit": "4.1.*"
24
+ },
25
+ "time": "2014-06-23 16:25:28",
26
+ "type": "composer-installer",
27
+ "extra": {
28
+ "class": "Composer\\Installers\\Installer",
29
+ "branch-alias": {
30
+ "dev-master": "1.0-dev"
31
+ }
32
+ },
33
+ "installation-source": "dist",
34
+ "autoload": {
35
+ "psr-0": {
36
+ "Composer\\Installers\\": "src/"
37
+ }
38
+ },
39
+ "notification-url": "https://packagist.org/downloads/",
40
+ "license": [
41
+ "MIT"
42
+ ],
43
+ "authors": [
44
+ {
45
+ "name": "Kyle Robinson Young",
46
+ "email": "kyle@dontkry.com",
47
+ "homepage": "https://github.com/shama",
48
+ "role": "Developer"
49
+ }
50
+ ],
51
+ "description": "A multi-framework Composer library installer",
52
+ "homepage": "http://composer.github.com/installers/",
53
+ "keywords": [
54
+ "Craft",
55
+ "Dolibarr",
56
+ "Hurad",
57
+ "MODX Evo",
58
+ "OXID",
59
+ "WolfCMS",
60
+ "agl",
61
+ "annotatecms",
62
+ "bitrix",
63
+ "cakephp",
64
+ "codeigniter",
65
+ "concrete5",
66
+ "croogo",
67
+ "drupal",
68
+ "elgg",
69
+ "fuelphp",
70
+ "installer",
71
+ "joomla",
72
+ "kohana",
73
+ "laravel",
74
+ "lithium",
75
+ "magento",
76
+ "mako",
77
+ "mediawiki",
78
+ "modulework",
79
+ "moodle",
80
+ "phpbb",
81
+ "piwik",
82
+ "ppi",
83
+ "roundcube",
84
+ "shopware",
85
+ "silverstripe",
86
+ "symfony",
87
+ "typo3",
88
+ "wordpress",
89
+ "zend",
90
+ "zikula"
91
+ ]
92
+ },
93
+ {
94
+ "name": "twig/twig",
95
+ "version": "v1.15.1",
96
+ "version_normalized": "1.15.1.0",
97
+ "source": {
98
+ "type": "git",
99
+ "url": "https://github.com/fabpot/Twig.git",
100
+ "reference": "1fb5784662f438d7d96a541e305e28b812e2eeed"
101
+ },
102
+ "dist": {
103
+ "type": "zip",
104
+ "url": "https://api.github.com/repos/fabpot/Twig/zipball/1fb5784662f438d7d96a541e305e28b812e2eeed",
105
+ "reference": "1fb5784662f438d7d96a541e305e28b812e2eeed",
106
+ "shasum": ""
107
+ },
108
+ "require": {
109
+ "php": ">=5.2.4"
110
+ },
111
+ "time": "2014-02-13 10:19:29",
112
+ "type": "library",
113
+ "extra": {
114
+ "branch-alias": {
115
+ "dev-master": "1.15-dev"
116
+ }
117
+ },
118
+ "installation-source": "dist",
119
+ "autoload": {
120
+ "psr-0": {
121
+ "Twig_": "lib/"
122
+ }
123
+ },
124
+ "notification-url": "https://packagist.org/downloads/",
125
+ "license": [
126
+ "BSD-3-Clause"
127
+ ],
128
+ "authors": [
129
+ {
130
+ "name": "Fabien Potencier",
131
+ "email": "fabien@symfony.com",
132
+ "homepage": "http://fabien.potencier.org",
133
+ "role": "Lead Developer"
134
+ },
135
+ {
136
+ "name": "Armin Ronacher2",
137
+ "email": "armin.ronacher@active-4.com",
138
+ "role": "Project Founder"
139
+ },
140
+ {
141
+ "name": "Twig Team",
142
+ "homepage": "https://github.com/fabpot/Twig/graphs/contributors",
143
+ "role": "Contributors"
144
+ }
145
+ ],
146
+ "description": "Twig, the flexible, fast, and secure template language for PHP",
147
+ "homepage": "http://twig.sensiolabs.org",
148
+ "keywords": [
149
+ "templating"
150
+ ]
151
+ },
152
+ {
153
+ "name": "asm89/twig-cache-extension",
154
+ "version": "0.1.0",
155
+ "version_normalized": "0.1.0.0",
156
+ "source": {
157
+ "type": "git",
158
+ "url": "https://github.com/asm89/twig-cache-extension.git",
159
+ "reference": "35da9579dc0648e5bb52d02530ff81352f7e1247"
160
+ },
161
+ "dist": {
162
+ "type": "zip",
163
+ "url": "https://api.github.com/repos/asm89/twig-cache-extension/zipball/35da9579dc0648e5bb52d02530ff81352f7e1247",
164
+ "reference": "35da9579dc0648e5bb52d02530ff81352f7e1247",
165
+ "shasum": ""
166
+ },
167
+ "require": {
168
+ "php": ">=5.3.2",
169
+ "twig/twig": "1.*"
170
+ },
171
+ "require-dev": {
172
+ "doctrine/cache": "1.*"
173
+ },
174
+ "time": "2013-11-13 20:03:36",
175
+ "type": "library",
176
+ "extra": {
177
+ "branch-alias": {
178
+ "dev-master": "0.1-dev"
179
+ }
180
+ },
181
+ "installation-source": "dist",
182
+ "autoload": {
183
+ "psr-0": {
184
+ "Asm89\\Twig\\CacheExtension\\": "lib/"
185
+ }
186
+ },
187
+ "notification-url": "https://packagist.org/downloads/",
188
+ "license": [
189
+ "MIT"
190
+ ],
191
+ "authors": [
192
+ {
193
+ "name": "Alexander",
194
+ "email": "iam.asm89@gmail.com",
195
+ "homepage": "http://asm89.github.io/"
196
+ }
197
+ ],
198
+ "description": "Caching template fragments with Twig.",
199
+ "homepage": "https://github.com/asm89/twig-cache-extension",
200
+ "keywords": [
201
+ "cache",
202
+ "extension",
203
+ "twig"
204
+ ]
205
+ },
206
+ {
207
+ "name": "symfony/yaml",
208
+ "version": "v2.5.0",
209
+ "version_normalized": "2.5.0.0",
210
+ "target-dir": "Symfony/Component/Yaml",
211
+ "source": {
212
+ "type": "git",
213
+ "url": "https://github.com/symfony/Yaml.git",
214
+ "reference": "b4b09c68ec2f2727574544ef0173684281a5033c"
215
+ },
216
+ "dist": {
217
+ "type": "zip",
218
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/b4b09c68ec2f2727574544ef0173684281a5033c",
219
+ "reference": "b4b09c68ec2f2727574544ef0173684281a5033c",
220
+ "shasum": ""
221
+ },
222
+ "require": {
223
+ "php": ">=5.3.3"
224
+ },
225
+ "time": "2014-05-16 14:25:18",
226
+ "type": "library",
227
+ "extra": {
228
+ "branch-alias": {
229
+ "dev-master": "2.5-dev"
230
+ }
231
+ },
232
+ "installation-source": "dist",
233
+ "autoload": {
234
+ "psr-0": {
235
+ "Symfony\\Component\\Yaml\\": ""
236
+ }
237
+ },
238
+ "notification-url": "https://packagist.org/downloads/",
239
+ "license": [
240
+ "MIT"
241
+ ],
242
+ "authors": [
243
+ {
244
+ "name": "Fabien Potencier",
245
+ "email": "fabien@symfony.com",
246
+ "homepage": "http://fabien.potencier.org",
247
+ "role": "Lead Developer"
248
+ },
249
+ {
250
+ "name": "Symfony Community",
251
+ "homepage": "http://symfony.com/contributors"
252
+ }
253
+ ],
254
+ "description": "Symfony Yaml Component",
255
+ "homepage": "http://symfony.com"
256
+ },
257
+ {
258
+ "name": "dannyvankooten/php-router",
259
+ "version": "dev-master",
260
+ "version_normalized": "9999999-dev",
261
+ "source": {
262
+ "type": "git",
263
+ "url": "https://github.com/dannyvankooten/PHP-Router.git",
264
+ "reference": "e9a479820b871ae4493fec30d5e433456767a505"
265
+ },
266
+ "dist": {
267
+ "type": "zip",
268
+ "url": "https://api.github.com/repos/dannyvankooten/PHP-Router/zipball/896472302cd1c0d0b6269b3837e7ca636a5b9b3a",
269
+ "reference": "e9a479820b871ae4493fec30d5e433456767a505",
270
+ "shasum": ""
271
+ },
272
+ "require": {
273
+ "php": ">=5.3.3",
274
+ "symfony/yaml": "@dev"
275
+ },
276
+ "require-dev": {
277
+ "phpunit/phpunit": "3.7.*"
278
+ },
279
+ "time": "2014-02-12 12:10:38",
280
+ "type": "library",
281
+ "installation-source": "source",
282
+ "autoload": {
283
+ "psr-0": {
284
+ "PHPRouter": "src/"
285
+ }
286
+ },
287
+ "notification-url": "https://packagist.org/downloads/",
288
+ "license": [
289
+ "MIT"
290
+ ],
291
+ "authors": [
292
+ {
293
+ "name": "Danny van Kooten",
294
+ "email": "dannyvankooten@gmail.com",
295
+ "homepage": "http://dannyvankooten.com/"
296
+ },
297
+ {
298
+ "name": "Jefersson Nathan",
299
+ "email": "malukenho@phpse.net"
300
+ }
301
+ ],
302
+ "description": "Simple PHP Router, supports REST and reverse routing.",
303
+ "homepage": "https://github.com/dannyvankooten/PHP-Router",
304
+ "keywords": [
305
+ "php",
306
+ "rest",
307
+ "router",
308
+ "routing"
309
+ ]
310
+ }
311
+ ]
vendor/vendor/composer/installers/.editorconfig ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
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
vendor/vendor/composer/installers/.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ vendor/
2
+ composer.lock
3
+ .idea/
vendor/vendor/composer/installers/.travis.yml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.3
5
+ - 5.4
6
+
7
+ before_script:
8
+ - curl -s http://getcomposer.org/installer | php -- --quiet
9
+ - php composer.phar install --dev
10
+
11
+ script: phpunit
vendor/vendor/composer/installers/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2012 Kyle Robinson Young
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
vendor/vendor/composer/installers/README.md ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # A Multi-Framework [Composer](http://getcomposer.org) Library Installer
2
+
3
+ [![Build Status](https://secure.travis-ci.org/composer/installers.png)](http://travis-ci.org/composer/installers)
4
+
5
+ This is for PHP package authors to require in their `composer.json`. It will
6
+ install their package to the correct location based on the specified package
7
+ type.
8
+
9
+ The goal of `installers` is to be a simple package type to install path map.
10
+ Users can also customize the install path per package and package authors can
11
+ modify the package name upon installing.
12
+
13
+ `installers` isn't intended on replacing all custom installers. If your
14
+ package requires special installation handling then by all means, create a
15
+ custom installer to handle it.
16
+
17
+ **Natively Supported Frameworks**:
18
+
19
+ The following frameworks natively work with Composer and will be
20
+ installed to the default `vendor` directory. `composer/installers`
21
+ is not needed to install packages with these frameworks:
22
+
23
+ * Aura
24
+ * Symfony2
25
+ * Yii
26
+ * Yii2
27
+
28
+ **Current Supported Package Types**:
29
+
30
+ > Stable types are marked as **bold**, this means that installation paths
31
+ > for those type will not be changed. Any adjustment for those types would
32
+ > require creation of brand new type that will cover required changes.
33
+
34
+ | Framework | Types
35
+ | --------- | -----
36
+ | AGL | `agl-module`
37
+ | AnnotateCms | `annotatecms-module`<br>`annotatecms-component`<br>`annotatecms-service`
38
+ | Bitrix | `bitrix-module`<br>`bitrix-component`
39
+ | CakePHP 2+ | **`cakephp-plugin`**
40
+ | CodeIgniter | `codeigniter-library`<br>`codeigniter-third-party`<br>`codeigniter-module`
41
+ | concrete5 | `concrete5-block`<br>`concrete5-package`<br>`concrete5-theme`<br>`concrete5-update`
42
+ | Craft | `craft-plugin`
43
+ | Croogo | `croogo-plugin`<br>`croogo-theme`
44
+ | Dolibarr | `dolibarr-module`
45
+ | Drupal | <b>`drupal-module`<br>`drupal-theme`</b><br>`drupal-library`<br>`drupal-profile`<br>`drupal-drush`
46
+ | Elgg | `elgg-plugin`
47
+ | FuelPHP v1.x | `fuel-module`<br>`fuel-package`<br/>`fuel-theme`
48
+ | Hurad | `hurad-plugin`<br>`hurad-theme`
49
+ | Joomla | `joomla-component`<br>`joomla-module`<br>`joomla-template`<br>`joomla-plugin`<br>`joomla-library`
50
+ | Kirby | **`kirby-plugin`**
51
+ | Kohana | **`kohana-module`**
52
+ | Laravel | `laravel-library`
53
+ | Lithium | **`lithium-library`<br>`lithium-source`**
54
+ | Magento | `magento-library`<br>`magento-skin`<br>`magento-theme`
55
+ | Mako | `mako-package`
56
+ | MODX Evo | `modxevo-snippet`<br>`modxevo-plugin`<br>`modxevo-module`<br>`modxevo-template`<br>`modxevo-lib`
57
+ | MediaWiki | `mediawiki-extension`
58
+ | October | **`october-module`<br>`october-plugin`**
59
+ | OXID | `oxid-module`<br>`oxid-theme`<br>`oxid-out`
60
+ | MODULEWork | `modulework-module`
61
+ | Moodle | `moodle-*` (Please [check source](https://raw.githubusercontent.com/composer/installers/master/src/Composer/Installers/MoodleInstaller.php) for all supported types)
62
+ | Piwik | `piwik-plugin`
63
+ | phpBB | `phpbb-extension`<br>`phpbb-style`<br>`phpbb-language`
64
+ | Pimcore | `pimcore-plugin`
65
+ | PPI | **`ppi-module`**
66
+ | Roundcube | `roundcube-plugin`
67
+ | shopware | `shopware-backend-plugin`<br/>`shopware-core-plugin`<br/>`shopware-frontend-plugin`<br/>`shopware-theme`
68
+ | SilverStripe | `silverstripe-module`<br>`silverstripe-theme`
69
+ | symfony1 | **`symfony1-plugin`**
70
+ | Tusk | `tusk-task`<br>`tusk-command`<br>`tusk-asset`
71
+ | TYPO3 Flow | `typo3-flow-package`<br>`typo3-flow-framework`<br>`typo3-flow-plugin`<br>`typo3-flow-site`<br>`typo3-flow-boilerplate`<br>`typo3-flow-build`
72
+ | TYPO3 CMS | `typo3-cms-extension`
73
+ | Wolf CMS | `wolfcms-plugin`
74
+ | WordPress | <b>`wordpress-plugin`<br>`wordpress-theme`</b><br>`wordpress-muplugin`
75
+ | Zend | `zend-library`<br>`zend-extra`<br>`zend-module`
76
+ | Zikula | `zikula-module`<br>`zikula-theme`
77
+
78
+ ## Example `composer.json` File
79
+
80
+ This is an example for a CakePHP plugin. The only important parts to set in your
81
+ composer.json file are `"type": "cakephp-plugin"` which describes what your
82
+ package is and `"require": { "composer/installers": "~1.0" }` which tells composer
83
+ to load the custom installers.
84
+
85
+ ```json
86
+ {
87
+ "name": "you/ftp",
88
+ "type": "cakephp-plugin",
89
+ "require": {
90
+ "composer/installers": "~1.0"
91
+ }
92
+ }
93
+ ```
94
+
95
+ This would install your package to the `Plugin/Ftp/` folder of a CakePHP app
96
+ when a user runs `php composer.phar install`.
97
+
98
+ So submit your packages to [packagist.org](http://packagist.org)!
99
+
100
+ ## Custom Install Paths
101
+
102
+ If you are consuming a package that uses the `composer/installers` you can
103
+ override the install path with the following extra in your `composer.json`:
104
+
105
+ ```json
106
+ {
107
+ "extra": {
108
+ "installer-paths": {
109
+ "your/custom/path/{$name}/": ["shama/ftp", "vendor/package"]
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ A package type can have a custom installation path with a `type:` prefix.
116
+
117
+ ``` json
118
+ {
119
+ "extra": {
120
+ "installer-paths": {
121
+ "your/custom/path/{$name}/": ["type:wordpress-plugin"]
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ This would use your custom path for each of the listed packages. The available
128
+ variables to use in your paths are: `{$name}`, `{$vendor}`, `{$type}`.
129
+
130
+ ## Custom Install Names
131
+
132
+ If you're a package author and need your package to be named differently when
133
+ installed consider using the `installer-name` extra.
134
+
135
+ For example you have a package named `shama/cakephp-ftp` with the type
136
+ `cakephp-plugin`. Installing with `composer/installers` would install to the
137
+ path `Plugin/CakephpFtp`. Due to the strict naming conventions, you as a
138
+ package author actually need the package to be named and installed to
139
+ `Plugin/Ftp`. Using the following config within your **package** `composer.json`
140
+ will allow this:
141
+
142
+ ```json
143
+ {
144
+ "name": "shama/cakephp-ftp",
145
+ "type": "cakephp-plugin",
146
+ "extra": {
147
+ "installer-name": "Ftp"
148
+ }
149
+ }
150
+ ```
151
+
152
+ Please note the name entered into `installer-name` will be the final and will
153
+ not be inflected.
154
+
155
+ ## Contribute!
156
+
157
+ * [Fork and clone](https://help.github.com/articles/fork-a-repo).
158
+ * Run the command `php composer.phar install --dev` to install the dev
159
+ dependencies. See [Composer](https://github.com/composer/composer#installation--usage).
160
+ * Use the command `phpunit` to run the tests. See [PHPUnit](http://phpunit.de).
161
+ * Create a branch, commit, push and send us a
162
+ [pull request](https://help.github.com/articles/using-pull-requests).
163
+
164
+ To ensure a consistent code base, you should make sure the code follows the
165
+ [Coding Standards](http://symfony.com/doc/2.0/contributing/code/standards.html)
166
+ which we borrowed from Symfony.
167
+
168
+ If you would like to help, please take a look at the list of
169
+ [issues](https://github.com/composer/installers/issues).
170
+
171
+ ### Should we allow dynamic package types or paths? No.
172
+ What are they? The ability for a package author to determine where a package
173
+ will be installed either through setting the path directly in their
174
+ `composer.json` or through a dynamic package type: `"type":
175
+ "framework-install-here"`.
176
+
177
+ It has been proposed many times. Even implemented once early on and then
178
+ removed. `installers` won't do this because it would allow a single package
179
+ author to wipe out entire folders without the user's consent. That user would
180
+ then come here to yell at us.
vendor/vendor/composer/installers/composer.json ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "composer/installers",
3
+ "type": "composer-installer",
4
+ "license": "MIT",
5
+ "description": "A multi-framework Composer library installer",
6
+ "keywords": [
7
+ "installer",
8
+ "AGL",
9
+ "AnnotateCms",
10
+ "Bitrix",
11
+ "CakePHP",
12
+ "CodeIgniter",
13
+ "concrete5",
14
+ "Craft",
15
+ "Croogo",
16
+ "Dolibarr",
17
+ "Drupal",
18
+ "Elgg",
19
+ "FuelPHP",
20
+ "Hurad",
21
+ "Joomla",
22
+ "Kohana",
23
+ "Laravel",
24
+ "Lithium",
25
+ "Magento",
26
+ "Mako",
27
+ "MODX Evo",
28
+ "MediaWiki",
29
+ "OXID",
30
+ "MODULEWork",
31
+ "Moodle",
32
+ "Piwik",
33
+ "phpBB",
34
+ "PPI",
35
+ "Roundcube",
36
+ "shopware",
37
+ "SilverStripe",
38
+ "symfony",
39
+ "TYPO3",
40
+ "WolfCMS",
41
+ "WordPress",
42
+ "Zend",
43
+ "Zikula"
44
+ ],
45
+ "homepage": "http://composer.github.com/installers/",
46
+ "authors": [
47
+ {
48
+ "name": "Kyle Robinson Young",
49
+ "email": "kyle@dontkry.com",
50
+ "homepage": "https://github.com/shama"
51
+ }
52
+ ],
53
+ "autoload": {
54
+ "psr-0": { "Composer\\Installers\\": "src/" }
55
+ },
56
+ "extra": {
57
+ "class": "Composer\\Installers\\Installer",
58
+ "branch-alias": {
59
+ "dev-master": "1.0-dev"
60
+ }
61
+ },
62
+ "replace": {
63
+ "shama/baton": "*",
64
+ "roundcube/plugin-installer": "*"
65
+ },
66
+ "require-dev": {
67
+ "composer/composer": "1.0.*@dev",
68
+ "phpunit/phpunit": "4.1.*"
69
+ }
70
+ }
vendor/vendor/composer/installers/phpunit.xml.dist ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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="tests/bootstrap.php"
13
+ >
14
+ <testsuites>
15
+ <testsuite name="Installers Test Suite">
16
+ <directory>tests/Composer/Installers</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+
20
+ <filter>
21
+ <whitelist>
22
+ <directory>src/Composer/Installers</directory>
23
+ </whitelist>
24
+ </filter>
25
+ </phpunit>
vendor/vendor/composer/installers/src/Composer/Installers/AglInstaller.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class AglInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'More/{$name}/',
8
+ );
9
+
10
+ /**
11
+ * Format package name to CamelCase
12
+ */
13
+ public function inflectPackageVars($vars)
14
+ {
15
+ $vars['name'] = preg_replace_callback('/(?:^|_|-)(.?)/', function ($matches) {
16
+ return strtoupper($matches[1]);
17
+ }, $vars['name']);
18
+
19
+ return $vars;
20
+ }
21
+ }
vendor/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class AnnotateCmsInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'addons/modules/{$name}/',
8
+ 'component' => 'addons/components/{$name}/',
9
+ 'service' => 'addons/services/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ use Composer\Composer;
5
+ use Composer\Package\PackageInterface;
6
+
7
+ abstract class BaseInstaller
8
+ {
9
+ protected $locations = array();
10
+ protected $composer;
11
+ protected $package;
12
+
13
+ /**
14
+ * Initializes base installer.
15
+ *
16
+ * @param PackageInterface $package
17
+ * @param Composer $composer
18
+ */
19
+ public function __construct(PackageInterface $package = null, Composer $composer = null)
20
+ {
21
+ $this->composer = $composer;
22
+ $this->package = $package;
23
+ }
24
+
25
+ /**
26
+ * Return the install path based on package type.
27
+ *
28
+ * @param PackageInterface $package
29
+ * @param string $frameworkType
30
+ * @return string
31
+ */
32
+ public function getInstallPath(PackageInterface $package, $frameworkType = '')
33
+ {
34
+ $type = $this->package->getType();
35
+
36
+ $prettyName = $this->package->getPrettyName();
37
+ if (strpos($prettyName, '/') !== false) {
38
+ list($vendor, $name) = explode('/', $prettyName);
39
+ } else {
40
+ $vendor = '';
41
+ $name = $prettyName;
42
+ }
43
+
44
+ $availableVars = $this->inflectPackageVars(compact('name', 'vendor', 'type'));
45
+
46
+ $extra = $package->getExtra();
47
+ if (!empty($extra['installer-name'])) {
48
+ $availableVars['name'] = $extra['installer-name'];
49
+ }
50
+
51
+ if ($this->composer->getPackage()) {
52
+ $extra = $this->composer->getPackage()->getExtra();
53
+ if (!empty($extra['installer-paths'])) {
54
+ $customPath = $this->mapCustomInstallPaths($extra['installer-paths'], $prettyName, $type);
55
+ if ($customPath !== false) {
56
+ return $this->templatePath($customPath, $availableVars);
57
+ }
58
+ }
59
+ }
60
+
61
+ $packageType = substr($type, strlen($frameworkType) + 1);
62
+ $locations = $this->getLocations();
63
+ if (!isset($locations[$packageType])) {
64
+ throw new \InvalidArgumentException(sprintf('Package type "%s" is not supported', $type));
65
+ }
66
+
67
+ return $this->templatePath($locations[$packageType], $availableVars);
68
+ }
69
+
70
+ /**
71
+ * For an installer to override to modify the vars per installer.
72
+ *
73
+ * @param array $vars
74
+ * @return array
75
+ */
76
+ public function inflectPackageVars($vars)
77
+ {
78
+ return $vars;
79
+ }
80
+
81
+ /**
82
+ * Gets the installer's locations
83
+ *
84
+ * @return array
85
+ */
86
+ public function getLocations()
87
+ {
88
+ return $this->locations;
89
+ }
90
+
91
+ /**
92
+ * Replace vars in a path
93
+ *
94
+ * @param string $path
95
+ * @param array $vars
96
+ * @return string
97
+ */
98
+ protected function templatePath($path, array $vars = array())
99
+ {
100
+ if (strpos($path, '{') !== false) {
101
+ extract($vars);
102
+ preg_match_all('@\{\$([A-Za-z0-9_]*)\}@i', $path, $matches);
103
+ if (!empty($matches[1])) {
104
+ foreach ($matches[1] as $var) {
105
+ $path = str_replace('{$' . $var . '}', $$var, $path);
106
+ }
107
+ }
108
+ }
109
+
110
+ return $path;
111
+ }
112
+
113
+ /**
114
+ * Search through a passed paths array for a custom install path.
115
+ *
116
+ * @param array $paths
117
+ * @param string $name
118
+ * @param string $type
119
+ * @return string
120
+ */
121
+ protected function mapCustomInstallPaths(array $paths, $name, $type)
122
+ {
123
+ foreach ($paths as $path => $names) {
124
+ if (in_array($name, $names) || in_array('type:' . $type, $names)) {
125
+ return $path;
126
+ }
127
+ }
128
+
129
+ return false;
130
+ }
131
+ }
vendor/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class BitrixInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'local/modules/{$name}/',
8
+ 'component' => 'local/components/{$name}/',
9
+ );
10
+ }
vendor/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ use Composer\DependencyResolver\Pool;
5
+ use Composer\Package\PackageInterface;
6
+ use Composer\Package\LinkConstraint\MultiConstraint;
7
+ use Composer\Package\LinkConstraint\VersionConstraint;
8
+
9
+ class CakePHPInstaller extends BaseInstaller
10
+ {
11
+ protected $locations = array(
12
+ 'plugin' => 'Plugin/{$name}/',
13
+ );
14
+
15
+ /**
16
+ * Format package name to CamelCase
17
+ */
18
+ public function inflectPackageVars($vars)
19
+ {
20
+ $nameParts = explode('/', $vars['name']);
21
+ foreach ($nameParts as &$value) {
22
+ $value = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $value));
23
+ $value = str_replace(array('-', '_'), ' ', $value);
24
+ $value = str_replace(' ', '', ucwords($value));
25
+ }
26
+ $vars['name'] = implode('/', $nameParts);
27
+
28
+ return $vars;
29
+ }
30
+
31
+ /**
32
+ * Change the default plugin location when cakephp >= 3.0
33
+ */
34
+ public function getLocations() {
35
+ $repositoryManager = $this->composer->getRepositoryManager();
36
+ if ($repositoryManager) {
37
+ $repos = $repositoryManager->getLocalRepository();
38
+ if (!$repos) {
39
+ return $this->locations;
40
+ }
41
+ $cake3 = new MultiConstraint(array(
42
+ new VersionConstraint('>=', '3.0.0'),
43
+ new VersionConstraint('!=', '9999999-dev'),
44
+ ));
45
+ $pool = new Pool('dev');
46
+ $pool->addRepository($repos);
47
+ $packages = $pool->whatProvides('cakephp/cakephp');
48
+ foreach ($packages as $package) {
49
+ $installed = new VersionConstraint('=', $package->getVersion());
50
+ if ($cake3->matches($installed)) {
51
+ $this->locations['plugin'] = 'plugins/{$name}/';
52
+ break;
53
+ }
54
+ }
55
+ }
56
+ return $this->locations;
57
+ }
58
+ }
vendor/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class CodeIgniterInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'library' => 'application/libraries/{$name}/',
8
+ 'third-party' => 'application/third_party/{$name}/',
9
+ 'module' => 'application/modules/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class Concrete5Installer extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'block' => 'blocks/{$name}/',
8
+ 'package' => 'packages/{$name}/',
9
+ 'theme' => 'themes/{$name}/',
10
+ 'update' => 'updates/{$name}/',
11
+ );
12
+ }
vendor/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class CraftInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'craft/plugins/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class CroogoInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'Plugin/{$name}/',
8
+ 'theme' => 'View/Themed/{$name}/',
9
+ );
10
+
11
+ /**
12
+ * Format package name to CamelCase
13
+ */
14
+ public function inflectPackageVars($vars)
15
+ {
16
+ $vars['name'] = strtolower(str_replace(array('-', '_'), ' ', $vars['name']));
17
+ $vars['name'] = str_replace(' ', '', ucwords($vars['name']));
18
+
19
+ return $vars;
20
+ }
21
+ }
vendor/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * Class DolibarrInstaller
6
+ *
7
+ * @package Composer\Installers
8
+ * @author Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
9
+ */
10
+ class DolibarrInstaller extends BaseInstaller
11
+ {
12
+ //TODO: Add support for scripts and themes
13
+ protected $locations = array(
14
+ 'module' => 'htdocs/custom/{$name}/',
15
+ );
16
+ }
vendor/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class DrupalInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$name}/',
8
+ 'theme' => 'themes/{$name}/',
9
+ 'library' => 'libraries/{$name}/',
10
+ 'profile' => 'profiles/{$name}/',
11
+ 'drush' => 'drush/{$name}/',
12
+ );
13
+ }
vendor/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class ElggInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'mod/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class FuelInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'fuel/app/modules/{$name}/',
8
+ 'package' => 'fuel/packages/{$name}/',
9
+ 'theme' => 'fuel/themes/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class HuradInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'Plugin/{$name}/',
8
+ 'theme' => 'View/Themed/{$name}/',
9
+ );
10
+
11
+ /**
12
+ * Format package name to CamelCase
13
+ */
14
+ public function inflectPackageVars($vars)
15
+ {
16
+ $vars['name'] = strtolower(str_replace(array('-', '_'), ' ', $vars['name']));
17
+ $vars['name'] = str_replace(' ', '', ucwords($vars['name']));
18
+
19
+ return $vars;
20
+ }
21
+ }
vendor/vendor/composer/installers/src/Composer/Installers/Installer.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ use Composer\Installer\LibraryInstaller;
5
+ use Composer\Package\PackageInterface;
6
+ use Composer\Repository\InstalledRepositoryInterface;
7
+
8
+ class Installer extends LibraryInstaller
9
+ {
10
+ /**
11
+ * Package types to installer class map
12
+ *
13
+ * @var array
14
+ */
15
+ private $supportedTypes = array(
16
+ 'agl' => 'AglInstaller',
17
+ 'annotatecms' => 'AnnotateCmsInstaller',
18
+ 'bitrix' => 'BitrixInstaller',
19
+ 'cakephp' => 'CakePHPInstaller',
20
+ 'codeigniter' => 'CodeIgniterInstaller',
21
+ 'concrete5' => 'Concrete5Installer',
22
+ 'craft' => 'CraftInstaller',
23
+ 'croogo' => 'CroogoInstaller',
24
+ 'drupal' => 'DrupalInstaller',
25
+ 'dolibarr' => 'DolibarrInstaller',
26
+ 'elgg' => 'ElggInstaller',
27
+ 'piwik' => 'PiwikInstaller',
28
+ 'fuel' => 'FuelInstaller',
29
+ 'hurad' => 'HuradInstaller',
30
+ 'joomla' => 'JoomlaInstaller',
31
+ 'kirby' => 'KirbyInstaller',
32
+ 'kohana' => 'KohanaInstaller',
33
+ 'laravel' => 'LaravelInstaller',
34
+ 'lithium' => 'LithiumInstaller',
35
+ 'magento' => 'MagentoInstaller',
36
+ 'mako' => 'MakoInstaller',
37
+ 'modxevo' => 'MODXEvoInstaller',
38
+ 'mediawiki' => 'MediaWikiInstaller',
39
+ 'microweber' => 'MicroweberInstaller',
40
+ 'modulework' => 'MODULEWorkInstaller',
41
+ 'moodle' => 'MoodleInstaller',
42
+ 'october' => 'OctoberInstaller',
43
+ 'oxid' => 'OxidInstaller',
44
+ 'phpbb' => 'PhpBBInstaller',
45
+ 'piwik' => 'PiwikInstaller',
46
+ 'pimcore' => 'PimcoreInstaller',
47
+ 'ppi' => 'PPIInstaller',
48
+ 'roundcube' => 'RoundcubeInstaller',
49
+ 'shopware' => 'ShopwareInstaller',
50
+ 'silverstripe' => 'SilverStripeInstaller',
51
+ 'symfony1' => 'Symfony1Installer',
52
+ 'wolfcms' => 'WolfCMSInstaller',
53
+ 'wordpress' => 'WordPressInstaller',
54
+ 'zend' => 'ZendInstaller',
55
+ 'zikula' => 'ZikulaInstaller',
56
+ 'typo3-flow' => 'TYPO3FlowInstaller',
57
+ 'typo3-cms' => 'TYPO3CmsInstaller',
58
+ 'tusk' => 'TuskInstaller',
59
+ );
60
+
61
+ /**
62
+ * {@inheritDoc}
63
+ */
64
+ public function getInstallPath(PackageInterface $package)
65
+ {
66
+ $type = $package->getType();
67
+ $frameworkType = $this->findFrameworkType($type);
68
+
69
+ if ($frameworkType === false) {
70
+ throw new \InvalidArgumentException(
71
+ 'Sorry the package type of this package is not yet supported.'
72
+ );
73
+ }
74
+
75
+ $class = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType];
76
+ $installer = new $class($package, $this->composer);
77
+
78
+ return $installer->getInstallPath($package, $frameworkType);
79
+ }
80
+
81
+ public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
82
+ {
83
+ if (!$repo->hasPackage($package)) {
84
+ throw new \InvalidArgumentException('Package is not installed: '.$package);
85
+ }
86
+
87
+ $repo->removePackage($package);
88
+
89
+ $installPath = $this->getInstallPath($package);
90
+ $this->io->write(sprintf('Deleting %s - %s', $installPath, $this->filesystem->removeDirectory($installPath) ? '<comment>deleted</comment>' : '<error>not deleted</error>'));
91
+ }
92
+
93
+ /**
94
+ * {@inheritDoc}
95
+ */
96
+ public function supports($packageType)
97
+ {
98
+ $frameworkType = $this->findFrameworkType($packageType);
99
+
100
+ if ($frameworkType === false) {
101
+ return false;
102
+ }
103
+
104
+ $locationPattern = $this->getLocationPattern($frameworkType);
105
+
106
+ return preg_match('#' . $frameworkType . '-' . $locationPattern . '#', $packageType, $matches) === 1;
107
+ }
108
+
109
+ /**
110
+ * Finds a supported framework type if it exists and returns it
111
+ *
112
+ * @param string $type
113
+ * @return string
114
+ */
115
+ protected function findFrameworkType($type)
116
+ {
117
+ $frameworkType = false;
118
+
119
+ foreach ($this->supportedTypes as $key => $val) {
120
+ if ($key === substr($type, 0, strlen($key))) {
121
+ $frameworkType = substr($type, 0, strlen($key));
122
+ break;
123
+ }
124
+ }
125
+
126
+ return $frameworkType;
127
+ }
128
+
129
+ /**
130
+ * Get the second part of the regular expression to check for support of a
131
+ * package type
132
+ *
133
+ * @param string $frameworkType
134
+ * @return string
135
+ */
136
+ protected function getLocationPattern($frameworkType)
137
+ {
138
+ $pattern = false;
139
+ if (!empty($this->supportedTypes[$frameworkType])) {
140
+ $frameworkClass = 'Composer\\Installers\\' . $this->supportedTypes[$frameworkType];
141
+ /** @var BaseInstaller $framework */
142
+ $framework = new $frameworkClass(null, $this->composer);
143
+ $locations = array_keys($framework->getLocations());
144
+ $pattern = $locations ? '(' . implode('|', $locations) . ')' : false;
145
+ }
146
+
147
+ return $pattern ? : '(\w+)';
148
+ }
149
+ }
vendor/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class JoomlaInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'component' => 'components/{$name}/',
8
+ 'module' => 'modules/{$name}/',
9
+ 'template' => 'templates/{$name}/',
10
+ 'plugin' => 'plugins/{$name}/',
11
+ 'library' => 'libraries/{$name}/',
12
+ );
13
+
14
+ // TODO: Add inflector for mod_ and com_ names
15
+ }
vendor/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class KirbyInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'site/plugins/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class KohanaInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class LaravelInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'library' => 'libraries/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class LithiumInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'library' => 'libraries/{$name}/',
8
+ 'source' => 'libraries/_source/{$name}/',
9
+ );
10
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class MODULEWorkInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * An installer to handle MODX Evolution specifics when installing packages.
6
+ */
7
+ class MODXEvoInstaller extends BaseInstaller
8
+ {
9
+ protected $locations = array(
10
+ 'snippet' => 'assets/snippets/{$name}/',
11
+ 'plugin' => 'assets/plugins/{$name}/',
12
+ 'module' => 'assets/modules/{$name}/',
13
+ 'template' => 'assets/templates/{$name}/',
14
+ 'lib' => 'assets/lib/{$name}/'
15
+ );
16
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class MagentoInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'theme' => 'app/design/frontend/{$name}/',
8
+ 'skin' => 'skin/frontend/default/{$name}/',
9
+ 'library' => 'lib/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class MakoInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'package' => 'app/packages/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class MediaWikiInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'extension' => 'extensions/{$name}/',
8
+ 'skin' => 'skins/{$name}/',
9
+ );
10
+
11
+ /**
12
+ * Format package name.
13
+ *
14
+ * For package type mediawiki-extension, cut off a trailing '-extension' if present and transform
15
+ * to CamelCase keeping existing uppercase chars.
16
+ *
17
+ * For package type mediawiki-skin, cut off a trailing '-skin' if present.
18
+ *
19
+ */
20
+ public function inflectPackageVars($vars)
21
+ {
22
+
23
+ if ($vars['type'] === 'mediawiki-extension') {
24
+ return $this->inflectExtensionVars($vars);
25
+ }
26
+
27
+ if ($vars['type'] === 'mediawiki-skin') {
28
+ return $this->inflectSkinVars($vars);
29
+ }
30
+
31
+ return $vars;
32
+ }
33
+
34
+ protected function inflectExtensionVars($vars)
35
+ {
36
+ $vars['name'] = preg_replace('/-extension$/', '', $vars['name']);
37
+ $vars['name'] = str_replace('-', ' ', $vars['name']);
38
+ $vars['name'] = str_replace(' ', '', ucwords($vars['name']));
39
+
40
+ return $vars;
41
+ }
42
+
43
+ protected function inflectSkinVars($vars)
44
+ {
45
+ $vars['name'] = preg_replace('/-skin$/', '', $vars['name']);
46
+
47
+ return $vars;
48
+ }
49
+
50
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class MicroweberInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'userfiles/modules/{$name}/',
8
+ 'module-skin' => 'userfiles/modules/{$name}/templates/',
9
+ 'template' => 'userfiles/templates/{$name}/',
10
+ 'element' => 'userfiles/elements/{$name}/',
11
+ 'vendor' => 'vendor/{$name}/',
12
+ 'components' => 'components/{$name}/'
13
+ );
14
+
15
+ /**
16
+ * Format package name.
17
+ *
18
+ * For package type microweber-module, cut off a trailing '-module' if present
19
+ *
20
+ * For package type microweber-template, cut off a trailing '-template' if present.
21
+ *
22
+ */
23
+ public function inflectPackageVars($vars)
24
+ {
25
+ if ($vars['type'] === 'microweber-template') {
26
+ return $this->inflectTemplateVars($vars);
27
+ }
28
+ if ($vars['type'] === 'microweber-templates') {
29
+ return $this->inflectTemplatesVars($vars);
30
+ }
31
+ if ($vars['type'] === 'microweber-core') {
32
+ return $this->inflectCoreVars($vars);
33
+ }
34
+ if ($vars['type'] === 'microweber-adapter') {
35
+ return $this->inflectCoreVars($vars);
36
+ }
37
+ if ($vars['type'] === 'microweber-module') {
38
+ return $this->inflectModuleVars($vars);
39
+ }
40
+ if ($vars['type'] === 'microweber-modules') {
41
+ return $this->inflectModulesVars($vars);
42
+ }
43
+ if ($vars['type'] === 'microweber-skin') {
44
+ return $this->inflectSkinVars($vars);
45
+ }
46
+ if ($vars['type'] === 'microweber-element' or $vars['type'] === 'microweber-elements') {
47
+ return $this->inflectElementVars($vars);
48
+ }
49
+
50
+ return $vars;
51
+ }
52
+
53
+ protected function inflectTemplateVars($vars)
54
+ {
55
+ $vars['name'] = preg_replace('/-template$/', '', $vars['name']);
56
+ $vars['name'] = preg_replace('/template-$/', '', $vars['name']);
57
+
58
+ return $vars;
59
+ }
60
+
61
+ protected function inflectTemplatesVars($vars)
62
+ {
63
+ $vars['name'] = preg_replace('/-templates$/', '', $vars['name']);
64
+ $vars['name'] = preg_replace('/templates-$/', '', $vars['name']);
65
+
66
+ return $vars;
67
+ }
68
+
69
+ protected function inflectCoreVars($vars)
70
+ {
71
+ $vars['name'] = preg_replace('/-providers$/', '', $vars['name']);
72
+ $vars['name'] = preg_replace('/-provider$/', '', $vars['name']);
73
+ $vars['name'] = preg_replace('/-adapter$/', '', $vars['name']);
74
+
75
+ return $vars;
76
+ }
77
+
78
+ protected function inflectModuleVars($vars)
79
+ {
80
+ $vars['name'] = preg_replace('/-module$/', '', $vars['name']);
81
+ $vars['name'] = preg_replace('/module-$/', '', $vars['name']);
82
+
83
+ return $vars;
84
+ }
85
+
86
+ protected function inflectModulesVars($vars)
87
+ {
88
+ $vars['name'] = preg_replace('/-modules$/', '', $vars['name']);
89
+ $vars['name'] = preg_replace('/modules-$/', '', $vars['name']);
90
+
91
+ return $vars;
92
+ }
93
+
94
+ protected function inflectSkinVars($vars)
95
+ {
96
+ $vars['name'] = preg_replace('/-skin$/', '', $vars['name']);
97
+ $vars['name'] = preg_replace('/skin-$/', '', $vars['name']);
98
+
99
+ return $vars;
100
+ }
101
+
102
+ protected function inflectElementVars($vars)
103
+ {
104
+ $vars['name'] = preg_replace('/-elements$/', '', $vars['name']);
105
+ $vars['name'] = preg_replace('/elements-$/', '', $vars['name']);
106
+ $vars['name'] = preg_replace('/-element$/', '', $vars['name']);
107
+ $vars['name'] = preg_replace('/element-$/', '', $vars['name']);
108
+
109
+ return $vars;
110
+ }
111
+ }
vendor/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class MoodleInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'mod' => 'mod/{$name}/',
8
+ 'report' => 'admin/report/{$name}/',
9
+ 'tool' => 'admin/tool/{$name}/',
10
+ 'assignment' => 'mod/assignment/type/{$name}/',
11
+ 'assignsubmission' => 'mod/assign/submission/{$name}/',
12
+ 'assignfeedback' => 'mod/assign/feedback/{$name}/',
13
+ 'auth' => 'auth/{$name}/',
14
+ 'availability' => 'availability/condition/{$name}/',
15
+ 'block' => 'blocks/{$name}/',
16
+ 'calendartype' => 'calendar/type/{$name}/',
17
+ 'format' => 'course/format/{$name}/',
18
+ 'coursereport' => 'course/report/{$name}/',
19
+ 'datafield' => 'mod/data/field/{$name}/',
20
+ 'datapreset' => 'mod/data/preset/{$name}/',
21
+ 'editor' => 'lib/editor/{$name}/',
22
+ 'enrol' => 'enrol/{$name}/',
23
+ 'filter' => 'filter/{$name}/',
24
+ 'gradeexport' => 'grade/export/{$name}/',
25
+ 'gradeimport' => 'grade/import/{$name}/',
26
+ 'gradereport' => 'grade/report/{$name}/',
27
+ 'gradingform' => 'grade/grading/form/{$name}/',
28
+ 'local' => 'local/{$name}/',
29
+ 'message' => 'message/output/{$name}/',
30
+ 'plagiarism' => 'plagiarism/{$name}/',
31
+ 'portfolio' => 'portfolio/{$name}/',
32
+ 'qbehaviour' => 'question/behaviour/{$name}/',
33
+ 'qformat' => 'question/format/{$name}/',
34
+ 'qtype' => 'question/type/{$name}/',
35
+ 'quizaccess' => 'mod/quiz/accessrule/{$name}/',
36
+ 'quiz' => 'mod/quiz/report/{$name}/',
37
+ 'report' => 'report/{$name}/',
38
+ 'repository' => 'repository/{$name}/',
39
+ 'scormreport' => 'mod/scorm/report/{$name}/',
40
+ 'theme' => 'theme/{$name}/',
41
+ 'profilefield' => 'user/profile/field/{$name}/',
42
+ 'webservice' => 'webservice/{$name}/',
43
+ 'workshopallocation' => 'mod/workshop/allocation/{$name}/',
44
+ 'workshopeval' => 'mod/workshop/eval/{$name}/',
45
+ 'workshopform' => 'mod/workshop/form/{$name}/'
46
+ );
47
+ }
vendor/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class OctoberInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$name}/',
8
+ 'plugin' => 'plugins/{$vendor}/{$name}/',
9
+ );
10
+ }
vendor/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class OxidInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$name}/',
8
+ 'theme' => 'application/views/{$name}/',
9
+ 'out' => 'out/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class PPIInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class PhpBBInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'extension' => 'ext/{$vendor}/{$name}/',
8
+ 'language' => 'language/{$name}/',
9
+ 'style' => 'styles/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class PimcoreInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'plugins/{$name}/',
8
+ );
9
+
10
+ /**
11
+ * Format package name to CamelCase
12
+ */
13
+ public function inflectPackageVars($vars)
14
+ {
15
+ $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name']));
16
+ $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']);
17
+ $vars['name'] = str_replace(' ', '', ucwords($vars['name']));
18
+
19
+ return $vars;
20
+ }
21
+ }
vendor/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * Class PiwikInstaller
6
+ *
7
+ * @package Composer\Installers
8
+ */
9
+ class PiwikInstaller extends BaseInstaller
10
+ {
11
+ /**
12
+ * @var array
13
+ */
14
+ protected $locations = array(
15
+ 'plugin' => 'plugins/{$name}/',
16
+ );
17
+
18
+ /**
19
+ * Format package name to CamelCase
20
+ * @param array $vars
21
+ *
22
+ * @return array
23
+ */
24
+ public function inflectPackageVars($vars)
25
+ {
26
+ $vars['name'] = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $vars['name']));
27
+ $vars['name'] = str_replace(array('-', '_'), ' ', $vars['name']);
28
+ $vars['name'] = str_replace(' ', '', ucwords($vars['name']));
29
+
30
+ return $vars;
31
+ }
32
+ }
vendor/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class RoundcubeInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'plugins/{$name}/',
8
+ );
9
+
10
+ /**
11
+ * Lowercase name and changes the name to a underscores
12
+ *
13
+ * @param array $vars
14
+ * @return array
15
+ */
16
+ public function inflectPackageVars($vars)
17
+ {
18
+ $vars['name'] = strtolower(str_replace('-', '_', $vars['name']));
19
+
20
+ return $vars;
21
+ }
22
+ }
vendor/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * Plugin/theme installer for shopware
6
+ * @author Benjamin Boit
7
+ */
8
+ class ShopwareInstaller extends BaseInstaller
9
+ {
10
+ protected $locations = array(
11
+ 'backend-plugin' => 'engine/Shopware/Plugins/Local/Backend/{$name}/',
12
+ 'core-plugin' => 'engine/Shopware/Plugins/Local/Core/{$name}/',
13
+ 'frontend-plugin' => 'engine/Shopware/Plugins/Local/Frontend/{$name}/',
14
+ 'theme' => 'templates/{$name}/'
15
+ );
16
+
17
+ /**
18
+ * Transforms the names
19
+ * @param array $vars
20
+ * @return array
21
+ */
22
+ public function inflectPackageVars($vars)
23
+ {
24
+ if ($vars['type'] === 'shopware-theme') {
25
+ return $this->correctThemeName($vars);
26
+ } else {
27
+ return $this->correctPluginName($vars);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Changes the name to a camelcased combination of vendor and name
33
+ * @param array $vars
34
+ * @return array
35
+ */
36
+ private function correctPluginName($vars)
37
+ {
38
+ $camelCasedName = preg_replace_callback('/(-[a-z])/', function ($matches) {
39
+ return strtoupper($matches[0][1]);
40
+ }, $vars['name']);
41
+
42
+ $vars['name'] = ucfirst($vars['vendor']) . ucfirst($camelCasedName);
43
+
44
+ return $vars;
45
+ }
46
+
47
+ /**
48
+ * Changes the name to a underscore separated name
49
+ * @param array $vars
50
+ * @return array
51
+ */
52
+ private function correctThemeName($vars)
53
+ {
54
+ $vars['name'] = str_replace('-', '_', $vars['name']);
55
+
56
+ return $vars;
57
+ }
58
+ }
vendor/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ use Composer\Package\PackageInterface;
5
+
6
+ class SilverStripeInstaller extends BaseInstaller
7
+ {
8
+ protected $locations = array(
9
+ 'module' => '{$name}/',
10
+ 'theme' => 'themes/{$name}/',
11
+ );
12
+
13
+ /**
14
+ * Return the install path based on package type.
15
+ *
16
+ * Relies on built-in BaseInstaller behaviour with one exception: silverstripe/framework
17
+ * must be installed to 'sapphire' and not 'framework' if the version is <3.0.0
18
+ *
19
+ * @param PackageInterface $package
20
+ * @param string $frameworkType
21
+ * @return string
22
+ */
23
+ public function getInstallPath(PackageInterface $package, $frameworkType = '')
24
+ {
25
+ if (
26
+ $package->getName() == 'silverstripe/framework'
27
+ && preg_match('/^\d+\.\d+\.\d+/', $package->getVersion())
28
+ && version_compare($package->getVersion(), '2.999.999') < 0
29
+ ) {
30
+ return $this->templatePath($this->locations['module'], array('name' => 'sapphire'));
31
+ } else {
32
+ return parent::getInstallPath($package, $frameworkType);
33
+ }
34
+
35
+ }
36
+ }
vendor/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * Plugin installer for symfony 1.x
6
+ *
7
+ * @author Jérôme Tamarelle <jerome@tamarelle.net>
8
+ */
9
+ class Symfony1Installer extends BaseInstaller
10
+ {
11
+ protected $locations = array(
12
+ 'plugin' => 'plugins/{$name}/',
13
+ );
14
+
15
+ /**
16
+ * Format package name to CamelCase
17
+ */
18
+ public function inflectPackageVars($vars)
19
+ {
20
+ $vars['name'] = preg_replace_callback('/(-[a-z])/', function ($matches) {
21
+ return strtoupper($matches[0][1]);
22
+ }, $vars['name']);
23
+
24
+ return $vars;
25
+ }
26
+ }
vendor/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * Extension installer for TYPO3 CMS
6
+ *
7
+ * @author Sascha Egerer <sascha.egerer@dkd.de>
8
+ */
9
+ class TYPO3CmsInstaller extends BaseInstaller
10
+ {
11
+ protected $locations = array(
12
+ 'extension' => 'typo3conf/ext/{$name}/',
13
+ );
14
+ }
vendor/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ /**
5
+ * An installer to handle TYPO3 Flow specifics when installing packages.
6
+ */
7
+ class TYPO3FlowInstaller extends BaseInstaller
8
+ {
9
+ protected $locations = array(
10
+ 'package' => 'Packages/Application/{$name}/',
11
+ 'framework' => 'Packages/Framework/{$name}/',
12
+ 'plugin' => 'Packages/Plugins/{$name}/',
13
+ 'site' => 'Packages/Sites/{$name}/',
14
+ 'boilerplate' => 'Packages/Boilerplates/{$name}/',
15
+ 'build' => 'Build/{$name}/',
16
+ );
17
+
18
+ /**
19
+ * Modify the package name to be a TYPO3 Flow style key.
20
+ *
21
+ * @param array $vars
22
+ * @return array
23
+ */
24
+ public function inflectPackageVars($vars)
25
+ {
26
+ $autoload = $this->package->getAutoload();
27
+ if (isset($autoload['psr-0']) && is_array($autoload['psr-0'])) {
28
+ $namespace = key($autoload['psr-0']);
29
+ $vars['name'] = str_replace('\\', '.', $namespace);
30
+ }
31
+ if (isset($autoload['psr-4']) && is_array($autoload['psr-4'])) {
32
+ $namespace = key($autoload['psr-4']);
33
+ $vars['name'] = rtrim(str_replace('\\', '.', $namespace), '.');
34
+ }
35
+
36
+ return $vars;
37
+ }
38
+ }
vendor/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+ /**
4
+ * Composer installer for 3rd party Tusk utilities
5
+ * @author Drew Ewing <drew@phenocode.com>
6
+ */
7
+ class TuskInstaller extends BaseInstaller
8
+ {
9
+ protected $locations = array(
10
+ 'task' => '.tusk/tasks/{$name}/',
11
+ 'command' => '.tusk/commands/{$name}/',
12
+ 'asset' => 'assets/tusk/{$name}/',
13
+ );
14
+ }
vendor/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class WolfCMSInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'wolf/plugins/{$name}/',
8
+ );
9
+ }
vendor/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class WordPressInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'plugin' => 'wp-content/plugins/{$name}/',
8
+ 'theme' => 'wp-content/themes/{$name}/',
9
+ 'muplugin' => 'wp-content/mu-plugins/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class ZendInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'library' => 'library/{$name}/',
8
+ 'extra' => 'extras/library/{$name}/',
9
+ 'module' => 'module/{$name}/',
10
+ );
11
+ }
vendor/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers;
3
+
4
+ class ZikulaInstaller extends BaseInstaller
5
+ {
6
+ protected $locations = array(
7
+ 'module' => 'modules/{$vendor}-{$name}/',
8
+ 'theme' => 'themes/{$vendor}-{$name}/'
9
+ );
10
+ }
vendor/vendor/composer/installers/src/bootstrap.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function includeIfExists($file)
3
+ {
4
+ if (file_exists($file)) {
5
+ return include $file;
6
+ }
7
+ }
8
+ if ((!$loader = includeIfExists(__DIR__ . '/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__ . '/../../../autoload.php'))) {
9
+ die('You must set up the project dependencies, run the following commands:'.PHP_EOL.
10
+ 'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
11
+ 'php composer.phar install'.PHP_EOL);
12
+ }
13
+ return $loader;
vendor/vendor/composer/installers/tests/Composer/Installers/Test/CakePHPInstallerTest.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers\Test;
3
+
4
+ use Composer\Installers\CakePHPInstaller;
5
+ use Composer\Repository\RepositoryManager;
6
+ use Composer\Repository\InstalledArrayRepository;
7
+ use Composer\Package\Package;
8
+ use Composer\Package\RootPackage;
9
+ use Composer\Package\Link;
10
+ use Composer\Package\Version\VersionParser;
11
+ use Composer\Composer;
12
+
13
+ class CakePHPInstallerTest extends TestCase
14
+ {
15
+ private $composer;
16
+ private $io;
17
+
18
+ /**
19
+ * setUp
20
+ *
21
+ * @return void
22
+ */
23
+ public function setUp()
24
+ {
25
+ $this->package = new Package('CamelCased', '1.0', '1.0');
26
+ $this->io = $this->getMock('Composer\IO\PackageInterface');
27
+ $this->composer = new Composer();
28
+ }
29
+
30
+ /**
31
+ * testInflectPackageVars
32
+ *
33
+ * @return void
34
+ */
35
+ public function testInflectPackageVars()
36
+ {
37
+ $installer = new CakePHPInstaller($this->package, $this->composer);
38
+ $result = $installer->inflectPackageVars(array('name' => 'CamelCased'));
39
+ $this->assertEquals($result, array('name' => 'CamelCased'));
40
+
41
+ $installer = new CakePHPInstaller($this->package, $this->composer);
42
+ $result = $installer->inflectPackageVars(array('name' => 'with-dash'));
43
+ $this->assertEquals($result, array('name' => 'WithDash'));
44
+
45
+ $installer = new CakePHPInstaller($this->package, $this->composer);
46
+ $result = $installer->inflectPackageVars(array('name' => 'with_underscore'));
47
+ $this->assertEquals($result, array('name' => 'WithUnderscore'));
48
+
49
+ $installer = new CakePHPInstaller($this->package, $this->composer);
50
+ $result = $installer->inflectPackageVars(array('name' => 'cake/acl'));
51
+ $this->assertEquals($result, array('name' => 'Cake/Acl'));
52
+
53
+ $installer = new CakePHPInstaller($this->package, $this->composer);
54
+ $result = $installer->inflectPackageVars(array('name' => 'cake/debug-kit'));
55
+ $this->assertEquals($result, array('name' => 'Cake/DebugKit'));
56
+ }
57
+
58
+ /**
59
+ * Test getLocations returning appropriate values based on CakePHP version
60
+ *
61
+ */
62
+ public function testGetLocations() {
63
+ $package = new RootPackage('CamelCased', '1.0', '1.0');
64
+ $composer = new Composer();
65
+ $rm = new RepositoryManager(
66
+ $this->getMock('Composer\IO\IOInterface'),
67
+ $this->getMock('Composer\Config')
68
+ );
69
+ $composer->setRepositoryManager($rm);
70
+ $installer = new CakePHPInstaller($package, $composer);
71
+
72
+ // 2.0 < cakephp < 3.0
73
+ $this->setCakephpVersion($rm, '2.0.0');
74
+ $result = $installer->getLocations();
75
+ $this->assertContains('Plugin/', $result['plugin']);
76
+
77
+ $this->setCakephpVersion($rm, '2.5.9');
78
+ $result = $installer->getLocations();
79
+ $this->assertContains('Plugin/', $result['plugin']);
80
+
81
+ $this->setCakephpVersion($rm, '~2.5');
82
+ $result = $installer->getLocations();
83
+ $this->assertContains('Plugin/', $result['plugin']);
84
+
85
+ // special handling for 2.x versions when 3.x is still in development
86
+ $this->setCakephpVersion($rm, 'dev-master');
87
+ $result = $installer->getLocations();
88
+ $this->assertContains('Plugin/', $result['plugin']);
89
+
90
+ $this->setCakephpVersion($rm, '>=2.5');
91
+ $result = $installer->getLocations();
92
+ $this->assertContains('Plugin/', $result['plugin']);
93
+
94
+ // cakephp >= 3.0
95
+ $this->setCakephpVersion($rm, '3.0.*-dev');
96
+ $result = $installer->getLocations();
97
+ $this->assertContains('plugins/', $result['plugin']);
98
+
99
+ $this->setCakephpVersion($rm, '~8.8');
100
+ $result = $installer->getLocations();
101
+ $this->assertContains('plugins/', $result['plugin']);
102
+ }
103
+
104
+ protected function setCakephpVersion($rm, $version) {
105
+ $parser = new VersionParser();
106
+ list(, $version) = explode(' ', $parser->parseConstraints($version));
107
+ $installed = new InstalledArrayRepository();
108
+ $package = new Package('cakephp/cakephp', $version, $version);
109
+ $installed->addPackage($package);
110
+ $rm->setLocalRepository($installed);
111
+ }
112
+
113
+ }
vendor/vendor/composer/installers/tests/Composer/Installers/Test/InstallerTest.php ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers\Test;
3
+
4
+ use Composer\Installers\Installer;
5
+ use Composer\Util\Filesystem;
6
+ use Composer\Package\Package;
7
+ use Composer\Package\RootPackage;
8
+ use Composer\Composer;
9
+ use Composer\Config;
10
+
11
+ class InstallerTest extends TestCase
12
+ {
13
+ private $composer;
14
+ private $config;
15
+ private $vendorDir;
16
+ private $binDir;
17
+ private $dm;
18
+ private $repository;
19
+ private $io;
20
+ private $fs;
21
+
22
+ /**
23
+ * setUp
24
+ *
25
+ * @return void
26
+ */
27
+ public function setUp()
28
+ {
29
+ $this->fs = new Filesystem;
30
+
31
+ $this->composer = new Composer();
32
+ $this->config = new Config();
33
+ $this->composer->setConfig($this->config);
34
+
35
+ $this->vendorDir = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . 'baton-test-vendor';
36
+ $this->ensureDirectoryExistsAndClear($this->vendorDir);
37
+
38
+ $this->binDir = realpath(sys_get_temp_dir()) . DIRECTORY_SEPARATOR . 'baton-test-bin';
39
+ $this->ensureDirectoryExistsAndClear($this->binDir);
40
+
41
+ $this->config->merge(array(
42
+ 'config' => array(
43
+ 'vendor-dir' => $this->vendorDir,
44
+ 'bin-dir' => $this->binDir,
45
+ ),
46
+ ));
47
+
48
+ $this->dm = $this->getMockBuilder('Composer\Downloader\DownloadManager')
49
+ ->disableOriginalConstructor()
50
+ ->getMock();
51
+ $this->composer->setDownloadManager($this->dm);
52
+
53
+ $this->repository = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
54
+ $this->io = $this->getMock('Composer\IO\IOInterface');
55
+ }
56
+
57
+ /**
58
+ * tearDown
59
+ *
60
+ * @return void
61
+ */
62
+ public function tearDown()
63
+ {
64
+ $this->fs->removeDirectory($this->vendorDir);
65
+ $this->fs->removeDirectory($this->binDir);
66
+ }
67
+
68
+ /**
69
+ * testSupports
70
+ *
71
+ * @return void
72
+ *
73
+ * @dataProvider dataForTestSupport
74
+ */
75
+ public function testSupports($type, $expected)
76
+ {
77
+ $installer = new Installer($this->io, $this->composer);
78
+ $this->assertSame($expected, $installer->supports($type), sprintf('Failed to show support for %s', $type));
79
+ }
80
+
81
+ /**
82
+ * dataForTestSupport
83
+ */
84
+ public function dataForTestSupport()
85
+ {
86
+ return array(
87
+ array('agl-module', true),
88
+ array('annotatecms-module', true),
89
+ array('annotatecms-component', true),
90
+ array('annotatecms-service', true),
91
+ array('bitrix-module', true),
92
+ array('bitrix-component', true),
93
+ array('cakephp', false),
94
+ array('cakephp-', false),
95
+ array('cakephp-app', false),
96
+ array('cakephp-plugin', true),
97
+ array('codeigniter-app', false),
98
+ array('codeigniter-library', true),
99
+ array('codeigniter-third-party', true),
100
+ array('codeigniter-module', true),
101
+ array('concrete5-block', true),
102
+ array('concrete5-package', true),
103
+ array('concrete5-theme', true),
104
+ array('concrete5-update', true),
105
+ array('craft-plugin', true),
106
+ array('croogo-plugin', true),
107
+ array('croogo-theme', true),
108
+ array('drupal-module', true),
109
+ array('dolibarr-module', true),
110
+ array('elgg-plugin', true),
111
+ array('fuel-module', true),
112
+ array('fuel-package', true),
113
+ array('hurad-plugin', true),
114
+ array('hurad-theme', true),
115
+ array('joomla-library', true),
116
+ array('kirby-plugin', true),
117
+ array('kohana-module', true),
118
+ array('laravel-library', true),
119
+ array('lithium-library', true),
120
+ array('magento-library', true),
121
+ array('mako-package', true),
122
+ array('modxevo-snippet', true),
123
+ array('modxevo-plugin', true),
124
+ array('modxevo-module', true),
125
+ array('modxevo-template', true),
126
+ array('modxevo-lib', true),
127
+ array('mediawiki-extension', true),
128
+ array('mediawiki-skin', true),
129
+ array('microweber-module', true),
130
+ array('modulework-module', true),
131
+ array('moodle-mod', true),
132
+ array('october-module', true),
133
+ array('october-plugin', true),
134
+ array('piwik-plugin', true),
135
+ array('phpbb-extension', true),
136
+ array('pimcore-plugin', true),
137
+ array('ppi-module', true),
138
+ array('roundcube-plugin', true),
139
+ array('shopware-backend-plugin', true),
140
+ array('shopware-core-plugin', true),
141
+ array('shopware-frontend-plugin', true),
142
+ array('shopware-theme', true),
143
+ array('silverstripe-module', true),
144
+ array('silverstripe-theme', true),
145
+ array('symfony1-plugin', true),
146
+ array('tusk-task', true),
147
+ array('tusk-asset', true),
148
+ array('typo3-flow-plugin', true),
149
+ array('typo3-cms-extension', true),
150
+ array('wolfcms-plugin', true),
151
+ array('wordpress-plugin', true),
152
+ array('wordpress-core', false),
153
+ array('zend-library', true),
154
+ array('zikula-module', true),
155
+ array('zikula-theme', true),
156
+ );
157
+ }
158
+
159
+ /**
160
+ * testInstallPath
161
+ *
162
+ * @dataProvider dataForTestInstallPath
163
+ */
164
+ public function testInstallPath($type, $path, $name, $version = '1.0.0')
165
+ {
166
+ $installer = new Installer($this->io, $this->composer);
167
+ $package = new Package($name, $version, $version);
168
+
169
+ $package->setType($type);
170
+ $result = $installer->getInstallPath($package);
171
+ $this->assertEquals($path, $result);
172
+ }
173
+
174
+ /**
175
+ * dataFormTestInstallPath
176
+ */
177
+ public function dataForTestInstallPath()
178
+ {
179
+ return array(
180
+ array('agl-module', 'More/MyTestPackage/', 'agl/my_test-package'),
181
+ array('annotatecms-module', 'addons/modules/my_module/', 'vysinsky/my_module'),
182
+ array('annotatecms-component', 'addons/components/my_component/', 'vysinsky/my_component'),
183
+ array('annotatecms-service', 'addons/services/my_service/', 'vysinsky/my_service'),
184
+ array('bitrix-module', 'local/modules/my_module/', 'author/my_module'),
185
+ array('bitrix-component', 'local/components/my_component/', 'author/my_component'),
186
+ array('cakephp-plugin', 'Plugin/Ftp/', 'shama/ftp'),
187
+ array('codeigniter-library', 'application/libraries/my_package/', 'shama/my_package'),
188
+ array('codeigniter-module', 'application/modules/my_package/', 'shama/my_package'),
189
+ array('concrete5-block', 'blocks/concrete5_block/', 'remo/concrete5_block'),
190
+ array('concrete5-package', 'packages/concrete5_package/', 'remo/concrete5_package'),
191
+ array('concrete5-theme', 'themes/concrete5_theme/', 'remo/concrete5_theme'),
192
+ array('concrete5-update', 'updates/concrete5/', 'concrete5/concrete5'),
193
+ array('craft-plugin', 'craft/plugins/my_plugin/', 'mdcpepper/my_plugin'),
194
+ array('croogo-plugin', 'Plugin/Sitemaps/', 'fahad19/sitemaps'),
195
+ array('croogo-theme', 'View/Themed/Readable/', 'rchavik/readable'),
196
+ array('dolibarr-module', 'htdocs/custom/my_module/', 'shama/my_module'),
197
+ array('drupal-module', 'modules/my_module/', 'shama/my_module'),
198
+ array('drupal-theme', 'themes/my_module/', 'shama/my_module'),
199
+ array('drupal-profile', 'profiles/my_module/', 'shama/my_module'),
200
+ array('drupal-drush', 'drush/my_module/', 'shama/my_module'),
201
+ array('elgg-plugin', 'mod/sample_plugin/', 'test/sample_plugin'),
202
+ array('fuel-module', 'fuel/app/modules/module/', 'fuel/module'),
203
+ array('fuel-package', 'fuel/packages/orm/', 'fuel/orm'),
204
+ array('hurad-plugin', 'Plugin/Akismet/', 'atkrad/akismet'),
205
+ array('hurad-theme', 'View/Themed/Hurad2013/', 'atkrad/Hurad2013'),
206
+ array('joomla-plugin', 'plugins/my_plugin/', 'shama/my_plugin'),
207
+ array('kirby-plugin', 'site/plugins/my_plugin/', 'shama/my_plugin'),
208
+ array('kohana-module', 'modules/my_package/', 'shama/my_package'),
209
+ array('laravel-library', 'libraries/my_package/', 'shama/my_package'),
210
+ array('lithium-library', 'libraries/li3_test/', 'user/li3_test'),
211
+ array('magento-library', 'lib/foo/', 'test/foo'),
212
+ array('modxevo-snippet', 'assets/snippets/my_snippet/', 'shama/my_snippet'),
213
+ array('modxevo-plugin', 'assets/plugins/my_plugin/', 'shama/my_plugin'),
214
+ array('modxevo-module', 'assets/modules/my_module/', 'shama/my_module'),
215
+ array('modxevo-template', 'assets/templates/my_template/', 'shama/my_template'),
216
+ array('modxevo-lib', 'assets/lib/my_lib/', 'shama/my_lib'),
217
+ array('mako-package', 'app/packages/my_package/', 'shama/my_package'),
218
+ array('mediawiki-extension', 'extensions/APC/', 'author/APC'),
219
+ array('mediawiki-extension', 'extensions/APC/', 'author/APC-extension'),
220
+ array('mediawiki-extension', 'extensions/UploadWizard/', 'author/upload-wizard'),
221
+ array('mediawiki-extension', 'extensions/SyntaxHighlight_GeSHi/', 'author/syntax-highlight_GeSHi'),
222
+ array('mediawiki-skin', 'skins/someskin/', 'author/someskin-skin'),
223
+ array('mediawiki-skin', 'skins/someskin/', 'author/someskin'),
224
+ array('microweber-module', 'userfiles/modules/my-thing/', 'author/my-thing-module'),
225
+ array('modulework-module', 'modules/my_package/', 'shama/my_package'),
226
+ array('moodle-mod', 'mod/my_package/', 'shama/my_package'),
227
+ array('october-module', 'modules/my_plugin/', 'shama/my_plugin'),
228
+ array('october-plugin', 'plugins/shama/my_plugin/', 'shama/my_plugin'),
229
+ array('piwik-plugin', 'plugins/VisitSummary/', 'shama/visit-summary'),
230
+ array('phpbb-extension', 'ext/test/foo/', 'test/foo'),
231
+ array('phpbb-style', 'styles/foo/', 'test/foo'),
232
+ array('phpbb-language', 'language/foo/', 'test/foo'),
233
+ array('pimcore-plugin', 'plugins/MyPlugin/', 'ubikz/my_plugin'),
234
+ array('ppi-module', 'modules/foo/', 'test/foo'),
235
+ array('roundcube-plugin', 'plugins/base/', 'test/base'),
236
+ array('roundcube-plugin', 'plugins/replace_dash/', 'test/replace-dash'),
237
+ array('shopware-backend-plugin', 'engine/Shopware/Plugins/Local/Backend/ShamaMyBackendPlugin/', 'shama/my-backend-plugin'),
238
+ array('shopware-core-plugin', 'engine/Shopware/Plugins/Local/Core/ShamaMyCorePlugin/', 'shama/my-core-plugin'),
239
+ array('shopware-frontend-plugin', 'engine/Shopware/Plugins/Local/Frontend/ShamaMyFrontendPlugin/', 'shama/my-frontend-plugin'),
240
+ array('shopware-theme', 'templates/my_theme/', 'shama/my-theme'),
241
+ array('silverstripe-module', 'my_module/', 'shama/my_module'),
242
+ array('silverstripe-module', 'sapphire/', 'silverstripe/framework', '2.4.0'),
243
+ array('silverstripe-module', 'framework/', 'silverstripe/framework', '3.0.0'),
244
+ array('silverstripe-module', 'framework/', 'silverstripe/framework', '3.0.0-rc1'),
245
+ array('silverstripe-module', 'framework/', 'silverstripe/framework', 'my/branch'),
246
+ array('silverstripe-theme', 'themes/my_theme/', 'shama/my_theme'),
247
+ array('symfony1-plugin', 'plugins/sfShamaPlugin/', 'shama/sfShamaPlugin'),
248
+ array('symfony1-plugin', 'plugins/sfShamaPlugin/', 'shama/sf-shama-plugin'),
249
+ array('tusk-task', '.tusk/tasks/my_task/', 'shama/my_task'),
250
+ array('typo3-flow-package', 'Packages/Application/my_package/', 'shama/my_package'),
251
+ array('typo3-flow-build', 'Build/my_package/', 'shama/my_package'),
252
+ array('typo3-cms-extension', 'typo3conf/ext/my_extension/', 'shama/my_extension'),
253
+ array('wolfcms-plugin', 'wolf/plugins/my_plugin/', 'shama/my_plugin'),
254
+ array('wordpress-plugin', 'wp-content/plugins/my_plugin/', 'shama/my_plugin'),
255
+ array('wordpress-muplugin', 'wp-content/mu-plugins/my_plugin/', 'shama/my_plugin'),
256
+ array('zend-extra', 'extras/library/zend_test/', 'shama/zend_test'),
257
+ array('zikula-module', 'modules/my-test_module/', 'my/test_module'),
258
+ array('zikula-theme', 'themes/my-test_theme/', 'my/test_theme'),
259
+ );
260
+ }
261
+
262
+ /**
263
+ * testGetCakePHPInstallPathException
264
+ *
265
+ * @return void
266
+ *
267
+ * @expectedException \InvalidArgumentException
268
+ */
269
+ public function testGetCakePHPInstallPathException()
270
+ {
271
+ $installer = new Installer($this->io, $this->composer);
272
+ $package = new Package('shama/ftp', '1.0.0', '1.0.0');
273
+
274
+ $package->setType('cakephp-whoops');
275
+ $result = $installer->getInstallPath($package);
276
+ }
277
+
278
+ /**
279
+ * testCustomInstallPath
280
+ */
281
+ public function testCustomInstallPath()
282
+ {
283
+ $installer = new Installer($this->io, $this->composer);
284
+ $package = new Package('shama/ftp', '1.0.0', '1.0.0');
285
+ $package->setType('cakephp-plugin');
286
+ $consumerPackage = new RootPackage('foo/bar', '1.0.0', '1.0.0');
287
+ $this->composer->setPackage($consumerPackage);
288
+ $consumerPackage->setExtra(array(
289
+ 'installer-paths' => array(
290
+ 'my/custom/path/{$name}/' => array(
291
+ 'shama/ftp',
292
+ 'foo/bar',
293
+ ),
294
+ ),
295
+ ));
296
+ $result = $installer->getInstallPath($package);
297
+ $this->assertEquals('my/custom/path/Ftp/', $result);
298
+ }
299
+
300
+ /**
301
+ * testCustomInstallerName
302
+ */
303
+ public function testCustomInstallerName()
304
+ {
305
+ $installer = new Installer($this->io, $this->composer);
306
+ $package = new Package('shama/cakephp-ftp-plugin', '1.0.0', '1.0.0');
307
+ $package->setType('cakephp-plugin');
308
+ $package->setExtra(array(
309
+ 'installer-name' => 'FTP',
310
+ ));
311
+ $result = $installer->getInstallPath($package);
312
+ $this->assertEquals('Plugin/FTP/', $result);
313
+ }
314
+
315
+ /**
316
+ * testCustomTypePath
317
+ */
318
+ public function testCustomTypePath()
319
+ {
320
+ $installer = new Installer($this->io, $this->composer);
321
+ $package = new Package('slbmeh/my_plugin', '1.0.0', '1.0.0');
322
+ $package->setType('wordpress-plugin');
323
+ $consumerPackage = new RootPackage('foo/bar', '1.0.0', '1.0.0');
324
+ $this->composer->setPackage($consumerPackage);
325
+ $consumerPackage->setExtra(array(
326
+ 'installer-paths' => array(
327
+ 'my/custom/path/{$name}/' => array(
328
+ 'type:wordpress-plugin'
329
+ ),
330
+ ),
331
+ ));
332
+ $result = $installer->getInstallPath($package);
333
+ $this->assertEquals('my/custom/path/my_plugin/', $result);
334
+ }
335
+
336
+ /**
337
+ * testNoVendorName
338
+ */
339
+ public function testNoVendorName()
340
+ {
341
+ $installer = new Installer($this->io, $this->composer);
342
+ $package = new Package('sfPhpunitPlugin', '1.0.0', '1.0.0');
343
+
344
+ $package->setType('symfony1-plugin');
345
+ $result = $installer->getInstallPath($package);
346
+ $this->assertEquals('plugins/sfPhpunitPlugin/', $result);
347
+ }
348
+
349
+ /**
350
+ * testTypo3Inflection
351
+ */
352
+ public function testTypo3Inflection()
353
+ {
354
+ $installer = new Installer($this->io, $this->composer);
355
+ $package = new Package('typo3/fluid', '1.0.0', '1.0.0');
356
+
357
+ $package->setAutoload(array(
358
+ 'psr-0' => array(
359
+ 'TYPO3\\Fluid' => 'Classes',
360
+ ),
361
+ ));
362
+
363
+ $package->setType('typo3-flow-package');
364
+ $result = $installer->getInstallPath($package);
365
+ $this->assertEquals('Packages/Application/TYPO3.Fluid/', $result);
366
+ }
367
+
368
+ public function testUninstallAndDeletePackageFromLocalRepo()
369
+ {
370
+ $package = new Package('foo', '1.0.0', '1.0.0');
371
+
372
+ $installer = $this->getMock('Composer\Installers\Installer', array('getInstallPath'), array($this->io, $this->composer));
373
+ $installer->expects($this->once())->method('getInstallPath')->with($package)->will($this->returnValue(sys_get_temp_dir().'/foo'));
374
+
375
+ $repo = $this->getMock('Composer\Repository\InstalledRepositoryInterface');
376
+ $repo->expects($this->once())->method('hasPackage')->with($package)->will($this->returnValue(true));
377
+ $repo->expects($this->once())->method('removePackage')->with($package);
378
+
379
+ $installer->uninstall($repo, $package);
380
+ }
381
+ }
vendor/vendor/composer/installers/tests/Composer/Installers/Test/MediaWikiInstallerTest.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers\Test;
3
+
4
+ use Composer\Installers\MediaWikiInstaller;
5
+ use Composer\Package\Package;
6
+ use Composer\Composer;
7
+
8
+ class MediaWikiInstallerTest extends \PHPUnit_Framework_TestCase
9
+ {
10
+ /**
11
+ * @var MediaWikiInstaller
12
+ */
13
+ private $installer;
14
+
15
+ public function setUp()
16
+ {
17
+ $this->installer = new MediaWikiInstaller(
18
+ new Package('NyanCat', '4.2', '4.2'),
19
+ new Composer()
20
+ );
21
+ }
22
+
23
+ /**
24
+ * @dataProvider packageNameInflectionProvider
25
+ */
26
+ public function testInflectPackageVars($type, $name, $expected)
27
+ {
28
+ $this->assertEquals(
29
+ $this->installer->inflectPackageVars(array('name' => $name, 'type'=>$type)),
30
+ array('name' => $expected, 'type'=>$type)
31
+ );
32
+ }
33
+
34
+ public function packageNameInflectionProvider()
35
+ {
36
+ return array(
37
+ array(
38
+ 'mediawiki-extension',
39
+ 'sub-page-list',
40
+ 'SubPageList',
41
+ ),
42
+ array(
43
+ 'mediawiki-extension',
44
+ 'sub-page-list-extension',
45
+ 'SubPageList',
46
+ ),
47
+ array(
48
+ 'mediawiki-extension',
49
+ 'semantic-mediawiki',
50
+ 'SemanticMediawiki',
51
+ ),
52
+ // tests that exactly one '-skin' is cut off, and that skins do not get ucwords treatment like extensions
53
+ array(
54
+ 'mediawiki-skin',
55
+ 'some-skin-skin',
56
+ 'some-skin',
57
+ ),
58
+ // tests that names without '-skin' suffix stay valid
59
+ array(
60
+ 'mediawiki-skin',
61
+ 'someotherskin',
62
+ 'someotherskin',
63
+ ),
64
+ );
65
+ }
66
+ }
vendor/vendor/composer/installers/tests/Composer/Installers/Test/PimcoreInstallerTest.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers\Test;
3
+
4
+ use Composer\Installers\PimcoreInstaller;
5
+ use Composer\Package\Package;
6
+ use Composer\Composer;
7
+
8
+ class PimcoreInstallerTest extends TestCase
9
+ {
10
+ private $composer;
11
+ private $io;
12
+
13
+ /**
14
+ * setUp
15
+ *
16
+ * @return void
17
+ */
18
+ public function setUp()
19
+ {
20
+ $this->package = new Package('CamelCased', '1.0', '1.0');
21
+ $this->io = $this->getMock('Composer\IO\PackageInterface');
22
+ $this->composer = new Composer();
23
+ }
24
+
25
+ /**
26
+ * testInflectPackageVars
27
+ *
28
+ * @return void
29
+ */
30
+ public function testInflectPackageVars()
31
+ {
32
+ $installer = new PimcoreInstaller($this->package, $this->composer);
33
+ $result = $installer->inflectPackageVars(array('name' => 'CamelCased'));
34
+ $this->assertEquals($result, array('name' => 'CamelCased'));
35
+
36
+ $installer = new PimcoreInstaller($this->package, $this->composer);
37
+ $result = $installer->inflectPackageVars(array('name' => 'with-dash'));
38
+ $this->assertEquals($result, array('name' => 'WithDash'));
39
+
40
+ $installer = new PimcoreInstaller($this->package, $this->composer);
41
+ $result = $installer->inflectPackageVars(array('name' => 'with_underscore'));
42
+ $this->assertEquals($result, array('name' => 'WithUnderscore'));
43
+ }
44
+ }
vendor/vendor/composer/installers/tests/Composer/Installers/Test/PiwikInstallerTest.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Composer\Installers\Test;
3
+
4
+ use Composer\Composer;
5
+ use Composer\Installers\PiwikInstaller;
6
+ use Composer\Package\Package;
7
+ use Composer\Package\PackageInterface;
8
+
9
+ /**
10
+ * Class PiwikInstallerTest
11
+ *
12
+ * @package Composer\Installers\Test
13
+ */
14
+ class PiwikInstallerTest extends TestCase
15
+ {
16
+ /**
17
+ * @varComposer
18
+ */
19
+ private $composer;
20
+
21
+ /**
22
+ * @var PackageInterface
23
+ */
24
+ private $io;
25
+
26
+ /**
27
+ * @var Package
28
+ */
29
+ private $package;
30
+
31
+ /**
32
+ * setUp
33
+ *
34
+ * @return void
35
+ */
36
+ public function setUp()
37
+ {
38
+ $this->package = new Package('VisitSummary', '1.0', '1.0');
39
+ $this->io = $this->getMock('Composer\IO\PackageInterface');
40
+ $this->composer = new Composer();
41
+ }
42
+
43
+ /**
44
+ * testInflectPackageVars
45
+ *
46
+ * @return void
47
+ */
48
+ public function testInflectPackageVars()
49
+ {
50
+ $installer = new PiwikInstaller($this->package, $this->composer);
51
+ $result = $installer->inflectPackageVars(array('name' => 'VisitSummary'));
52
+ $this->assertEquals($result, array('name' => 'VisitSummary'));
53
+
54
+ $installer = new PiwikInstaller($this->package, $this->composer);
55
+ $result = $installer->inflectPackageVars(array('name' => 'visit-summary'));
56
+ $this->assertEquals($result, array('name' => 'VisitSummary'));
57
+
58
+ $installer = new PiwikInstaller($this->package, $this->composer);
59
+ $result = $installer->inflectPackageVars(array('name' => 'visit_summary'));
60
+ $this->assertEquals($result, array('name' => 'VisitSummary'));
61
+ }
62
+
63
+ }
vendor/vendor/composer/installers/tests/Composer/Installers/Test/TestCase.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Installers\Test;
14
+
15
+ use Composer\Package\Version\VersionParser;
16
+ use Composer\Package\Package;
17
+ use Composer\Package\AliasPackage;
18
+ use Composer\Package\LinkConstraint\VersionConstraint;
19
+ use Composer\Util\Filesystem;
20
+
21
+ abstract class TestCase extends \PHPUnit_Framework_TestCase
22
+ {
23
+ private static $parser;
24
+
25
+ protected static function getVersionParser()
26
+ {
27
+ if (!self::$parser) {
28
+ self::$parser = new VersionParser();
29
+ }
30
+
31
+ return self::$parser;
32
+ }
33
+
34
+ protected function getVersionConstraint($operator, $version)
35
+ {
36
+ return new VersionConstraint(
37
+ $operator,
38
+ self::getVersionParser()->normalize($version)
39
+ );
40
+ }
41
+
42
+ protected function getPackage($name, $version)
43
+ {
44
+ $normVersion = self::getVersionParser()->normalize($version);
45
+
46
+ return new Package($name, $normVersion, $version);
47
+ }
48
+
49
+ protected function getAliasPackage($package, $version)
50
+ {
51
+ $normVersion = self::getVersionParser()->normalize($version);
52
+
53
+ return new AliasPackage($package, $normVersion, $version);
54
+ }
55
+
56
+ protected function ensureDirectoryExistsAndClear($directory)
57
+ {
58
+ $fs = new Filesystem();
59
+ if (is_dir($directory)) {
60
+ $fs->removeDirectory($directory);
61
+ }
62
+ mkdir($directory, 0777, true);
63
+ }
64
+ }
vendor/vendor/composer/installers/tests/bootstrap.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+
3
+ $loader = require __DIR__ . '/../src/bootstrap.php';
4
+ $loader->add('Composer\Installers\Test', __DIR__);
vendor/vendor/dannyvankooten/php-router/.gitignore ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Compiled source #
2
+ ###################
3
+ *.com
4
+ *.class
5
+ *.dll
6
+ *.exe
7
+ *.o
8
+ *.so
9
+ *.sublime-project
10
+ *.sublime-workspace
11
+
12
+ # Packages #
13
+ ############
14
+ # it's better to unpack these files and commit the raw source
15
+ # git has its own built in compression methods
16
+ *.7z
17
+ *.dmg
18
+ *.gz
19
+ *.iso
20
+ *.jar
21
+ *.rar
22
+ *.tar
23
+ *.zip
24
+
25
+ # Logs and databases #
26
+ ######################
27
+ *.log
28
+ *.sql
29
+ *.sqlite
30
+
31
+ # OS generated files #
32
+ ######################
33
+ .DS_Store*
34
+ ehthumbs.db
35
+ Icon?
36
+ Thumbs.db
vendor/vendor/dannyvankooten/php-router/.htaccess ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ Options +FollowSymLinks
2
+ RewriteEngine On
3
+ RewriteRule ^(.*)$ example.php [NC,L]
vendor/vendor/dannyvankooten/php-router/LICENSE ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ Copyright (c) 2012 Danny van Kooten
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
vendor/vendor/dannyvankooten/php-router/README.md ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PHP Router class
2
+
3
+ A simple Rails inspired PHP router class.
4
+
5
+ * Usage of different HTTP Methods
6
+ * REST / Resourceful routing
7
+ * Reversed routing using named routes
8
+ * Dynamic URL's: use URL segments as parameters.
9
+
10
+ ## Usage
11
+ ```php
12
+ <?php
13
+ require 'Router.php';
14
+ require 'Route.php';
15
+
16
+ $router = new Router();
17
+
18
+ $router->setBasePath('/PHP-Router');
19
+
20
+ // defining routes can be as simple as this
21
+ $router->map('/', 'users#index');
22
+
23
+ // or somewhat more complicated
24
+ $router->map('/users/:id/edit/', array('controller' => 'SomeController', 'action' => 'someAction'), array('methods' => 'GET,PUT', 'name' => 'users_edit', 'filters' => array('id' => '(\d+)')));
25
+
26
+ // You can even specify closures as the Route's target
27
+ $router->map('/hello/:name', function($name) { echo "Hello $name."; });
28
+
29
+ // match current request URL & http method
30
+ $target = $router->matchCurrentRequest();
31
+ var_dump($target);
32
+
33
+ // generate an URL
34
+ $router->generate('users_edit', array('id' => 5));
35
+ ```
36
+
37
+ ## More information
38
+ Have a look at the example.php file or read trough the class' documentation for a better understanding on how to use this class.
39
+
40
+ If you like PHP Router you might also like [AltoRouter](//github.com/dannyvankooten/AltoRouter).
41
+
42
+ ## License
43
+ MIT Licensed, http://www.opensource.org/licenses/MIT
vendor/vendor/dannyvankooten/php-router/composer.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dannyvankooten/php-router",
3
+ "description": "Simple PHP Router, supports REST and reverse routing.",
4
+ "keywords": ["router", "routing", "php", "rest"],
5
+ "homepage": "https://github.com/dannyvankooten/PHP-Router",
6
+ "license": "MIT",
7
+ "authors": [
8
+ {
9
+ "name": "Danny van Kooten",
10
+ "email": "dannyvankooten@gmail.com",
11
+ "homepage": "http://dannyvankooten.com/"
12
+ },
13
+ {
14
+ "name": "Jefersson Nathan",
15
+ "email": "malukenho@phpse.net"
16
+ }
17
+ ],
18
+ "require": {
19
+ "php": ">=5.3.0"
20
+ },
21
+ "autoload": {
22
+ "psr-0": {
23
+ "PHProuter": "src/"
24
+ }
25
+ }
26
+ }
vendor/vendor/dannyvankooten/php-router/example.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require 'Router.php';
3
+ require 'Route.php';
4
+
5
+ $router = new Router();
6
+
7
+ $router->setBasePath('/PHP-Router');
8
+
9
+ $router->map('/', 'someController:indexAction', array('methods' => 'GET'));
10
+ $router->map('/users/','users#create', array('methods' => 'POST', 'name' => 'users_create'));
11
+ $router->map('/users/:id/edit/', 'users#edit', array('methods' => 'GET', 'name' => 'users_edit', 'filters' => array('id' => '(\d+)')));
12
+ $router->map('/contact/',array('controller' => 'someController', 'action' => 'contactAction'), array('name' => 'contact'));
13
+
14
+ $router->map('/blog/:slug', array('c' => 'BlogController', 'a' => 'showAction'));
15
+
16
+ // capture rest of URL in "path" parameter (including forward slashes)
17
+ $router->map('/site-section/:path','some#target',array( 'filters' => array( 'path' => '(.*)') ) );
18
+
19
+ $route = $router->matchCurrentRequest();
20
+
21
+ ?><h3>Current URL & HTTP method would route to: </h3>
22
+ <?php if($route) { ?>
23
+ <strong>Target:</strong>
24
+ <pre><?php var_dump($route->getTarget()); ?></pre>
25
+
26
+ <strong>Parameters:</strong>
27
+ <pre><?php var_dump($route->getParameters()); ?></pre>
28
+ <?php } else { ?>
29
+ <pre>No route matched.</pre>
30
+ <?php } ?>
31
+
32
+ <h3>Try out these URL's.</h3>
33
+ <p><a href="<?php echo $router->generate('users_edit', array('id' => 5)); ?>"><?php echo $router->generate('users_edit', array('id' => 5)); ?></a></p>
34
+ <p><a href="<?php echo $router->generate('contact'); ?>"><?php echo $router->generate('contact'); ?></a></p>
35
+ <p><form action="" method="POST"><input type="submit" value="Post request to current URL" /></form></p>
36
+ <p><form action="<?php echo $router->generate('users_create'); ?>" method="POST"><input type="submit" value="POST request to <?php echo $router->generate('users_create'); ?>" /></form></p>
37
+ <p><a href="<?php echo $router->generate('users_list'); ?>">GET request to <?php echo $router->generate('users_list'); ?></p>
vendor/vendor/dannyvankooten/php-router/src/PHPRouter/Route.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPRouter;
3
+
4
+ class Route
5
+ {
6
+ /**
7
+ * URL of this Route
8
+ * @var string
9
+ */
10
+ private $_url;
11
+
12
+ /**
13
+ * Accepted HTTP methods for this route
14
+ * @var array
15
+ */
16
+ private $_methods = array('GET','POST','PUT','DELETE');
17
+
18
+ /**
19
+ * Target for this route, can be anything.
20
+ * @var mixed
21
+ */
22
+ private $_target;
23
+
24
+ /**
25
+ * The name of this route, used for reversed routing
26
+ * @var string
27
+ */
28
+ private $_name;
29
+
30
+ /**
31
+ * Custom parameter filters for this route
32
+ * @var array
33
+ */
34
+ private $_filters = array();
35
+
36
+ /**
37
+ * Array containing parameters passed through request URL
38
+ * @var array
39
+ */
40
+ private $_parameters = array();
41
+
42
+ public function getUrl()
43
+ {
44
+ return $this->_url;
45
+ }
46
+
47
+ public function setUrl($url)
48
+ {
49
+ $url = (string) $url;
50
+
51
+ // make sure that the URL is suffixed with a forward slash
52
+ if(substr($url,-1) !== '/') $url .= '/';
53
+
54
+ $this->_url = $url;
55
+ }
56
+
57
+ public function getTarget()
58
+ {
59
+ return $this->_target;
60
+ }
61
+
62
+ public function setTarget($target)
63
+ {
64
+ $this->_target = $target;
65
+ }
66
+
67
+ public function getMethods()
68
+ {
69
+ return $this->_methods;
70
+ }
71
+
72
+ public function setMethods(array $methods)
73
+ {
74
+ $this->_methods = $methods;
75
+ }
76
+
77
+ public function getName()
78
+ {
79
+ return $this->_name;
80
+ }
81
+
82
+ public function setName($name)
83
+ {
84
+ $this->_name = (string) $name;
85
+ }
86
+
87
+ public function setFilters(array $filters)
88
+ {
89
+ $this->_filters = $filters;
90
+ }
91
+
92
+ public function getRegex()
93
+ {
94
+ return preg_replace_callback("/:(\w+)/", array(&$this, 'substituteFilter'), $this->_url);
95
+ }
96
+
97
+ private function substituteFilter($matches)
98
+ {
99
+ if (isset($matches[1]) && isset($this->_filters[$matches[1]])) {
100
+ return $this->_filters[$matches[1]];
101
+ }
102
+
103
+ return "([\w-]+)";
104
+ }
105
+
106
+ public function getParameters()
107
+ {
108
+ return $this->_parameters;
109
+ }
110
+
111
+ public function setParameters(array $parameters)
112
+ {
113
+ $this->_parameters = $parameters;
114
+ }
115
+ }
vendor/vendor/dannyvankooten/php-router/src/PHPRouter/Router.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPRouter;
3
+
4
+ /**
5
+ * Routing class to match request URL's against given routes and map them to a controller action.
6
+ */
7
+ class Router
8
+ {
9
+ /**
10
+ * Array that holds all Route objects
11
+ * @var array
12
+ */
13
+ private $_routes = array();
14
+
15
+ /**
16
+ * Array to store named routes in, used for reverse routing.
17
+ * @var array
18
+ */
19
+ private $_namedRoutes = array();
20
+
21
+ /**
22
+ * The base REQUEST_URI. Gets prepended to all route _url's.
23
+ * @var string
24
+ */
25
+ private $_basePath = '';
26
+
27
+ /**
28
+ * Set the base _url - gets prepended to all route _url's.
29
+ * @param string $base_url
30
+ */
31
+ public function setBasePath($basePath)
32
+ {
33
+ $this->_basePath = (string) $basePath;
34
+ }
35
+
36
+ /**
37
+ * Route factory method
38
+ *
39
+ * Maps the given URL to the given target.
40
+ * @param string $routeUrl string
41
+ * @param mixed $target The target of this route. Can be anything. You'll have to provide your own method to turn * this into a filename, controller / action pair, etc..
42
+ * @param array $args Array of optional arguments.
43
+ */
44
+ public function map($routeUrl, $target = '', array $args = array())
45
+ {
46
+ $route = new Route();
47
+
48
+ $route->setUrl($this->_basePath . $routeUrl);
49
+
50
+ $route->setTarget($target);
51
+
52
+ if(isset($args['methods'])) {
53
+ $methods = explode(',', $args['methods']);
54
+ $route->setMethods($methods);
55
+ }
56
+
57
+ if(isset($args['filters'])) {
58
+ $route->setFilters($args['filters']);
59
+ }
60
+
61
+ if(isset($args['name'])) {
62
+ $route->setName($args['name']);
63
+ if (!isset($this->_namedRoutes[$route->getName()])) {
64
+ $this->_namedRoutes[$route->getName()] = $route;
65
+ }
66
+ }
67
+
68
+ $this->_routes[] = $route;
69
+ }
70
+
71
+ /**
72
+ * Matches the current request against mapped routes
73
+ */
74
+ public function matchCurrentRequest()
75
+ {
76
+ $requestMethod = (isset($_POST['_method']) && ($_method = strtoupper($_POST['_method'])) && in_array($_method,array('PUT','DELETE'))) ? $_method : $_SERVER['REQUEST_METHOD'];
77
+ $requestUrl = $_SERVER['REQUEST_URI'];
78
+
79
+ // strip GET variables from URL
80
+ if(($pos = strpos($requestUrl, '?')) !== false) {
81
+ $requestUrl = substr($requestUrl, 0, $pos);
82
+ }
83
+
84
+ return $this->match($requestUrl, $requestMethod);
85
+ }
86
+
87
+ /**
88
+ * Match given request _url and request method and see if a route has been defined for it
89
+ * If so, return route's target
90
+ * If called multiple times
91
+ */
92
+ public function match($requestUrl, $requestMethod = 'GET')
93
+ {
94
+
95
+ foreach ($this->_routes as $route) {
96
+
97
+ // compare server request method with route's allowed http methods
98
+ if (! in_array($requestMethod, $route->getMethods())) {
99
+ continue;
100
+ }
101
+
102
+ // check if request _url matches route regex. if not, return false.
103
+ if (! preg_match("@^".$route->getRegex()."*$@i", $requestUrl, $matches)) {
104
+ continue;
105
+ }
106
+
107
+ $params = array();
108
+
109
+ if (preg_match_all("/:([\w-]+)/", $route->getUrl(), $argument_keys)) {
110
+
111
+ // grab array with matches
112
+ $argument_keys = $argument_keys[1];
113
+
114
+ // loop trough parameter names, store matching value in $params array
115
+ foreach ($argument_keys as $key => $name) {
116
+ if (isset($matches[$key + 1])) {
117
+ $params[$name] = $matches[$key + 1];
118
+ }
119
+ }
120
+
121
+ }
122
+
123
+ $route->setParameters($params);
124
+
125
+ return $route;
126
+ }
127
+ return false;
128
+ }
129
+
130
+
131
+
132
+ /**
133
+ * Reverse route a named route
134
+ *
135
+ * @param string $route_name The name of the route to reverse route.
136
+ * @param array $params Optional array of parameters to use in URL
137
+ * @return string The url to the route
138
+ */
139
+ public function generate($routeName, array $params = array())
140
+ {
141
+ // Check if route exists
142
+ if (! isset($this->_namedRoutes[$routeName])) {
143
+ throw new Exception("No route with the name $routeName has been found.");
144
+ }
145
+
146
+ $route = $this->_namedRoutes[$routeName];
147
+ $url = $route->getUrl();
148
+
149
+ // replace route url with given parameters
150
+ if ($params && preg_match_all("/:(\w+)/", $url, $param_keys))
151
+ {
152
+
153
+ // grab array with matches
154
+ $param_keys = $param_keys[1];
155
+
156
+ // loop trough parameter names, store matching value in $params array
157
+ foreach ($param_keys as $key) {
158
+ if (isset($params[$key]))
159
+ $url = preg_replace("/:(\w+)/", $params[$key], $url, 1);
160
+ }
161
+ }
162
+ return $url;
163
+ }
164
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ vendor/
2
+ composer.lock
3
+ phpunit.xml
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ CHANGELOG
2
+ =========
3
+
4
+ 2.1.0
5
+ -----
6
+
7
+ * Yaml::parse() does not evaluate loaded files as PHP files by default
8
+ anymore (call Yaml::enablePhpParsing() to get back the old behavior)
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Dumper.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml;
13
+
14
+ /**
15
+ * Dumper dumps PHP variables to YAML strings.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Dumper
20
+ {
21
+ /**
22
+ * The amount of spaces to use for indentation of nested nodes.
23
+ *
24
+ * @var int
25
+ */
26
+ protected $indentation = 4;
27
+
28
+ /**
29
+ * Sets the indentation.
30
+ *
31
+ * @param int $num The amount of spaces to use for indentation of nested nodes.
32
+ */
33
+ public function setIndentation($num)
34
+ {
35
+ $this->indentation = (int) $num;
36
+ }
37
+
38
+ /**
39
+ * Dumps a PHP value to YAML.
40
+ *
41
+ * @param mixed $input The PHP value
42
+ * @param int $inline The level where you switch to inline YAML
43
+ * @param int $indent The level of indentation (used internally)
44
+ * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
45
+ * @param bool $objectSupport true if object support is enabled, false otherwise
46
+ *
47
+ * @return string The YAML representation of the PHP value
48
+ */
49
+ public function dump($input, $inline = 0, $indent = 0, $exceptionOnInvalidType = false, $objectSupport = false)
50
+ {
51
+ $output = '';
52
+ $prefix = $indent ? str_repeat(' ', $indent) : '';
53
+
54
+ if ($inline <= 0 || !is_array($input) || empty($input)) {
55
+ $output .= $prefix.Inline::dump($input, $exceptionOnInvalidType, $objectSupport);
56
+ } else {
57
+ $isAHash = array_keys($input) !== range(0, count($input) - 1);
58
+
59
+ foreach ($input as $key => $value) {
60
+ $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
61
+
62
+ $output .= sprintf('%s%s%s%s',
63
+ $prefix,
64
+ $isAHash ? Inline::dump($key, $exceptionOnInvalidType, $objectSupport).':' : '-',
65
+ $willBeInlined ? ' ' : "\n",
66
+ $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $exceptionOnInvalidType, $objectSupport)
67
+ ).($willBeInlined ? "\n" : '');
68
+ }
69
+ }
70
+
71
+ return $output;
72
+ }
73
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Escaper.php ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml;
13
+
14
+ /**
15
+ * Escaper encapsulates escaping rules for single and double-quoted
16
+ * YAML strings.
17
+ *
18
+ * @author Matthew Lewinski <matthew@lewinski.org>
19
+ */
20
+ class Escaper
21
+ {
22
+ // Characters that would cause a dumped string to require double quoting.
23
+ const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
24
+
25
+ // Mapping arrays for escaping a double quoted string. The backslash is
26
+ // first to ensure proper escaping because str_replace operates iteratively
27
+ // on the input arrays. This ordering of the characters avoids the use of strtr,
28
+ // which performs more slowly.
29
+ private static $escapees = array('\\\\', '\\"', '"',
30
+ "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
31
+ "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
32
+ "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
33
+ "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
34
+ "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9");
35
+ private static $escaped = array('\\"', '\\\\', '\\"',
36
+ "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a",
37
+ "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f",
38
+ "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17",
39
+ "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f",
40
+ "\\N", "\\_", "\\L", "\\P");
41
+
42
+ /**
43
+ * Determines if a PHP value would require double quoting in YAML.
44
+ *
45
+ * @param string $value A PHP value
46
+ *
47
+ * @return bool True if the value would require double quotes.
48
+ */
49
+ public static function requiresDoubleQuoting($value)
50
+ {
51
+ return preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
52
+ }
53
+
54
+ /**
55
+ * Escapes and surrounds a PHP value with double quotes.
56
+ *
57
+ * @param string $value A PHP value
58
+ *
59
+ * @return string The quoted, escaped string
60
+ */
61
+ public static function escapeWithDoubleQuotes($value)
62
+ {
63
+ return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value));
64
+ }
65
+
66
+ /**
67
+ * Determines if a PHP value would require single quoting in YAML.
68
+ *
69
+ * @param string $value A PHP value
70
+ *
71
+ * @return bool True if the value would require single quotes.
72
+ */
73
+ public static function requiresSingleQuoting($value)
74
+ {
75
+ return preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value);
76
+ }
77
+
78
+ /**
79
+ * Escapes and surrounds a PHP value with single quotes.
80
+ *
81
+ * @param string $value A PHP value
82
+ *
83
+ * @return string The quoted, escaped string
84
+ */
85
+ public static function escapeWithSingleQuotes($value)
86
+ {
87
+ return sprintf("'%s'", str_replace('\'', '\'\'', $value));
88
+ }
89
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/DumpException.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Exception;
13
+
14
+ /**
15
+ * Exception class thrown when an error occurs during dumping.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ *
19
+ * @api
20
+ */
21
+ class DumpException extends RuntimeException
22
+ {
23
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/ExceptionInterface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Exception;
13
+
14
+ /**
15
+ * Exception interface for all exceptions thrown by the component.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ *
19
+ * @api
20
+ */
21
+ interface ExceptionInterface
22
+ {
23
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/ParseException.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Exception;
13
+
14
+ if (!defined('JSON_UNESCAPED_UNICODE')) {
15
+ define('JSON_UNESCAPED_SLASHES', 64);
16
+ define('JSON_UNESCAPED_UNICODE', 256);
17
+ }
18
+
19
+ /**
20
+ * Exception class thrown when an error occurs during parsing.
21
+ *
22
+ * @author Fabien Potencier <fabien@symfony.com>
23
+ *
24
+ * @api
25
+ */
26
+ class ParseException extends RuntimeException
27
+ {
28
+ private $parsedFile;
29
+ private $parsedLine;
30
+ private $snippet;
31
+ private $rawMessage;
32
+
33
+ /**
34
+ * Constructor.
35
+ *
36
+ * @param string $message The error message
37
+ * @param int $parsedLine The line where the error occurred
38
+ * @param int $snippet The snippet of code near the problem
39
+ * @param string $parsedFile The file name where the error occurred
40
+ * @param \Exception $previous The previous exception
41
+ */
42
+ public function __construct($message, $parsedLine = -1, $snippet = null, $parsedFile = null, \Exception $previous = null)
43
+ {
44
+ $this->parsedFile = $parsedFile;
45
+ $this->parsedLine = $parsedLine;
46
+ $this->snippet = $snippet;
47
+ $this->rawMessage = $message;
48
+
49
+ $this->updateRepr();
50
+
51
+ parent::__construct($this->message, 0, $previous);
52
+ }
53
+
54
+ /**
55
+ * Gets the snippet of code near the error.
56
+ *
57
+ * @return string The snippet of code
58
+ */
59
+ public function getSnippet()
60
+ {
61
+ return $this->snippet;
62
+ }
63
+
64
+ /**
65
+ * Sets the snippet of code near the error.
66
+ *
67
+ * @param string $snippet The code snippet
68
+ */
69
+ public function setSnippet($snippet)
70
+ {
71
+ $this->snippet = $snippet;
72
+
73
+ $this->updateRepr();
74
+ }
75
+
76
+ /**
77
+ * Gets the filename where the error occurred.
78
+ *
79
+ * This method returns null if a string is parsed.
80
+ *
81
+ * @return string The filename
82
+ */
83
+ public function getParsedFile()
84
+ {
85
+ return $this->parsedFile;
86
+ }
87
+
88
+ /**
89
+ * Sets the filename where the error occurred.
90
+ *
91
+ * @param string $parsedFile The filename
92
+ */
93
+ public function setParsedFile($parsedFile)
94
+ {
95
+ $this->parsedFile = $parsedFile;
96
+
97
+ $this->updateRepr();
98
+ }
99
+
100
+ /**
101
+ * Gets the line where the error occurred.
102
+ *
103
+ * @return int The file line
104
+ */
105
+ public function getParsedLine()
106
+ {
107
+ return $this->parsedLine;
108
+ }
109
+
110
+ /**
111
+ * Sets the line where the error occurred.
112
+ *
113
+ * @param int $parsedLine The file line
114
+ */
115
+ public function setParsedLine($parsedLine)
116
+ {
117
+ $this->parsedLine = $parsedLine;
118
+
119
+ $this->updateRepr();
120
+ }
121
+
122
+ private function updateRepr()
123
+ {
124
+ $this->message = $this->rawMessage;
125
+
126
+ $dot = false;
127
+ if ('.' === substr($this->message, -1)) {
128
+ $this->message = substr($this->message, 0, -1);
129
+ $dot = true;
130
+ }
131
+
132
+ if (null !== $this->parsedFile) {
133
+ $this->message .= sprintf(' in %s', json_encode($this->parsedFile, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
134
+ }
135
+
136
+ if ($this->parsedLine >= 0) {
137
+ $this->message .= sprintf(' at line %d', $this->parsedLine);
138
+ }
139
+
140
+ if ($this->snippet) {
141
+ $this->message .= sprintf(' (near "%s")', $this->snippet);
142
+ }
143
+
144
+ if ($dot) {
145
+ $this->message .= '.';
146
+ }
147
+ }
148
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Exception/RuntimeException.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Exception;
13
+
14
+ /**
15
+ * Exception class thrown when an error occurs during parsing.
16
+ *
17
+ * @author Romain Neutron <imprec@gmail.com>
18
+ *
19
+ * @api
20
+ */
21
+ class RuntimeException extends \RuntimeException implements ExceptionInterface
22
+ {
23
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Inline.php ADDED
@@ -0,0 +1,487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml;
13
+
14
+ use Symfony\Component\Yaml\Exception\ParseException;
15
+ use Symfony\Component\Yaml\Exception\DumpException;
16
+
17
+ /**
18
+ * Inline implements a YAML parser/dumper for the YAML inline syntax.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class Inline
23
+ {
24
+ const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
25
+
26
+ private static $exceptionOnInvalidType = false;
27
+ private static $objectSupport = false;
28
+
29
+ /**
30
+ * Converts a YAML string to a PHP array.
31
+ *
32
+ * @param string $value A YAML string
33
+ * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
34
+ * @param bool $objectSupport true if object support is enabled, false otherwise
35
+ *
36
+ * @return array A PHP array representing the YAML string
37
+ *
38
+ * @throws ParseException
39
+ */
40
+ public static function parse($value, $exceptionOnInvalidType = false, $objectSupport = false)
41
+ {
42
+ self::$exceptionOnInvalidType = $exceptionOnInvalidType;
43
+ self::$objectSupport = $objectSupport;
44
+
45
+ $value = trim($value);
46
+
47
+ if (0 == strlen($value)) {
48
+ return '';
49
+ }
50
+
51
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
52
+ $mbEncoding = mb_internal_encoding();
53
+ mb_internal_encoding('ASCII');
54
+ }
55
+
56
+ $i = 0;
57
+ switch ($value[0]) {
58
+ case '[':
59
+ $result = self::parseSequence($value, $i);
60
+ ++$i;
61
+ break;
62
+ case '{':
63
+ $result = self::parseMapping($value, $i);
64
+ ++$i;
65
+ break;
66
+ default:
67
+ $result = self::parseScalar($value, null, array('"', "'"), $i);
68
+ }
69
+
70
+ // some comments are allowed at the end
71
+ if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
72
+ throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)));
73
+ }
74
+
75
+ if (isset($mbEncoding)) {
76
+ mb_internal_encoding($mbEncoding);
77
+ }
78
+
79
+ return $result;
80
+ }
81
+
82
+ /**
83
+ * Dumps a given PHP variable to a YAML string.
84
+ *
85
+ * @param mixed $value The PHP variable to convert
86
+ * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
87
+ * @param bool $objectSupport true if object support is enabled, false otherwise
88
+ *
89
+ * @return string The YAML string representing the PHP array
90
+ *
91
+ * @throws DumpException When trying to dump PHP resource
92
+ */
93
+ public static function dump($value, $exceptionOnInvalidType = false, $objectSupport = false)
94
+ {
95
+ switch (true) {
96
+ case is_resource($value):
97
+ if ($exceptionOnInvalidType) {
98
+ throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
99
+ }
100
+
101
+ return 'null';
102
+ case is_object($value):
103
+ if ($objectSupport) {
104
+ return '!!php/object:'.serialize($value);
105
+ }
106
+
107
+ if ($exceptionOnInvalidType) {
108
+ throw new DumpException('Object support when dumping a YAML file has been disabled.');
109
+ }
110
+
111
+ return 'null';
112
+ case is_array($value):
113
+ return self::dumpArray($value, $exceptionOnInvalidType, $objectSupport);
114
+ case null === $value:
115
+ return 'null';
116
+ case true === $value:
117
+ return 'true';
118
+ case false === $value:
119
+ return 'false';
120
+ case ctype_digit($value):
121
+ return is_string($value) ? "'$value'" : (int) $value;
122
+ case is_numeric($value):
123
+ $locale = setlocale(LC_NUMERIC, 0);
124
+ if (false !== $locale) {
125
+ setlocale(LC_NUMERIC, 'C');
126
+ }
127
+ $repr = is_string($value) ? "'$value'" : (is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : strval($value));
128
+
129
+ if (false !== $locale) {
130
+ setlocale(LC_NUMERIC, $locale);
131
+ }
132
+
133
+ return $repr;
134
+ case Escaper::requiresDoubleQuoting($value):
135
+ return Escaper::escapeWithDoubleQuotes($value);
136
+ case Escaper::requiresSingleQuoting($value):
137
+ return Escaper::escapeWithSingleQuotes($value);
138
+ case '' == $value:
139
+ return "''";
140
+ case preg_match(self::getTimestampRegex(), $value):
141
+ case in_array(strtolower($value), array('null', '~', 'true', 'false')):
142
+ return "'$value'";
143
+ default:
144
+ return $value;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Dumps a PHP array to a YAML string.
150
+ *
151
+ * @param array $value The PHP array to dump
152
+ * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
153
+ * @param bool $objectSupport true if object support is enabled, false otherwise
154
+ *
155
+ * @return string The YAML string representing the PHP array
156
+ */
157
+ private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
158
+ {
159
+ // array
160
+ $keys = array_keys($value);
161
+ if ((1 == count($keys) && '0' == $keys[0])
162
+ || (count($keys) > 1 && array_reduce($keys, function ($v, $w) { return (int) $v + $w; }, 0) == count($keys) * (count($keys) - 1) / 2)
163
+ ) {
164
+ $output = array();
165
+ foreach ($value as $val) {
166
+ $output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
167
+ }
168
+
169
+ return sprintf('[%s]', implode(', ', $output));
170
+ }
171
+
172
+ // mapping
173
+ $output = array();
174
+ foreach ($value as $key => $val) {
175
+ $output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
176
+ }
177
+
178
+ return sprintf('{ %s }', implode(', ', $output));
179
+ }
180
+
181
+ /**
182
+ * Parses a scalar to a YAML string.
183
+ *
184
+ * @param scalar $scalar
185
+ * @param string $delimiters
186
+ * @param array $stringDelimiters
187
+ * @param int &$i
188
+ * @param bool $evaluate
189
+ *
190
+ * @return string A YAML string
191
+ *
192
+ * @throws ParseException When malformed inline YAML string is parsed
193
+ */
194
+ public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
195
+ {
196
+ if (in_array($scalar[$i], $stringDelimiters)) {
197
+ // quoted scalar
198
+ $output = self::parseQuotedScalar($scalar, $i);
199
+
200
+ if (null !== $delimiters) {
201
+ $tmp = ltrim(substr($scalar, $i), ' ');
202
+ if (!in_array($tmp[0], $delimiters)) {
203
+ throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
204
+ }
205
+ }
206
+ } else {
207
+ // "normal" string
208
+ if (!$delimiters) {
209
+ $output = substr($scalar, $i);
210
+ $i += strlen($output);
211
+
212
+ // remove comments
213
+ if (false !== $strpos = strpos($output, ' #')) {
214
+ $output = rtrim(substr($output, 0, $strpos));
215
+ }
216
+ } elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
217
+ $output = $match[1];
218
+ $i += strlen($output);
219
+ } else {
220
+ throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
221
+ }
222
+
223
+ if ($evaluate) {
224
+ $output = self::evaluateScalar($output);
225
+ }
226
+ }
227
+
228
+ return $output;
229
+ }
230
+
231
+ /**
232
+ * Parses a quoted scalar to YAML.
233
+ *
234
+ * @param string $scalar
235
+ * @param int &$i
236
+ *
237
+ * @return string A YAML string
238
+ *
239
+ * @throws ParseException When malformed inline YAML string is parsed
240
+ */
241
+ private static function parseQuotedScalar($scalar, &$i)
242
+ {
243
+ if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
244
+ throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
245
+ }
246
+
247
+ $output = substr($match[0], 1, strlen($match[0]) - 2);
248
+
249
+ $unescaper = new Unescaper();
250
+ if ('"' == $scalar[$i]) {
251
+ $output = $unescaper->unescapeDoubleQuotedString($output);
252
+ } else {
253
+ $output = $unescaper->unescapeSingleQuotedString($output);
254
+ }
255
+
256
+ $i += strlen($match[0]);
257
+
258
+ return $output;
259
+ }
260
+
261
+ /**
262
+ * Parses a sequence to a YAML string.
263
+ *
264
+ * @param string $sequence
265
+ * @param int &$i
266
+ *
267
+ * @return string A YAML string
268
+ *
269
+ * @throws ParseException When malformed inline YAML string is parsed
270
+ */
271
+ private static function parseSequence($sequence, &$i = 0)
272
+ {
273
+ $output = array();
274
+ $len = strlen($sequence);
275
+ $i += 1;
276
+
277
+ // [foo, bar, ...]
278
+ while ($i < $len) {
279
+ switch ($sequence[$i]) {
280
+ case '[':
281
+ // nested sequence
282
+ $output[] = self::parseSequence($sequence, $i);
283
+ break;
284
+ case '{':
285
+ // nested mapping
286
+ $output[] = self::parseMapping($sequence, $i);
287
+ break;
288
+ case ']':
289
+ return $output;
290
+ case ',':
291
+ case ' ':
292
+ break;
293
+ default:
294
+ $isQuoted = in_array($sequence[$i], array('"', "'"));
295
+ $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
296
+
297
+ if (!$isQuoted && false !== strpos($value, ': ')) {
298
+ // embedded mapping?
299
+ try {
300
+ $value = self::parseMapping('{'.$value.'}');
301
+ } catch (\InvalidArgumentException $e) {
302
+ // no, it's not
303
+ }
304
+ }
305
+
306
+ $output[] = $value;
307
+
308
+ --$i;
309
+ }
310
+
311
+ ++$i;
312
+ }
313
+
314
+ throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
315
+ }
316
+
317
+ /**
318
+ * Parses a mapping to a YAML string.
319
+ *
320
+ * @param string $mapping
321
+ * @param int &$i
322
+ *
323
+ * @return string A YAML string
324
+ *
325
+ * @throws ParseException When malformed inline YAML string is parsed
326
+ */
327
+ private static function parseMapping($mapping, &$i = 0)
328
+ {
329
+ $output = array();
330
+ $len = strlen($mapping);
331
+ $i += 1;
332
+
333
+ // {foo: bar, bar:foo, ...}
334
+ while ($i < $len) {
335
+ switch ($mapping[$i]) {
336
+ case ' ':
337
+ case ',':
338
+ ++$i;
339
+ continue 2;
340
+ case '}':
341
+ return $output;
342
+ }
343
+
344
+ // key
345
+ $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
346
+
347
+ // value
348
+ $done = false;
349
+ while ($i < $len) {
350
+ switch ($mapping[$i]) {
351
+ case '[':
352
+ // nested sequence
353
+ $value = self::parseSequence($mapping, $i);
354
+ // Spec: Keys MUST be unique; first one wins.
355
+ // Parser cannot abort this mapping earlier, since lines
356
+ // are processed sequentially.
357
+ if (!isset($output[$key])) {
358
+ $output[$key] = $value;
359
+ }
360
+ $done = true;
361
+ break;
362
+ case '{':
363
+ // nested mapping
364
+ $value = self::parseMapping($mapping, $i);
365
+ // Spec: Keys MUST be unique; first one wins.
366
+ // Parser cannot abort this mapping earlier, since lines
367
+ // are processed sequentially.
368
+ if (!isset($output[$key])) {
369
+ $output[$key] = $value;
370
+ }
371
+ $done = true;
372
+ break;
373
+ case ':':
374
+ case ' ':
375
+ break;
376
+ default:
377
+ $value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
378
+ // Spec: Keys MUST be unique; first one wins.
379
+ // Parser cannot abort this mapping earlier, since lines
380
+ // are processed sequentially.
381
+ if (!isset($output[$key])) {
382
+ $output[$key] = $value;
383
+ }
384
+ $done = true;
385
+ --$i;
386
+ }
387
+
388
+ ++$i;
389
+
390
+ if ($done) {
391
+ continue 2;
392
+ }
393
+ }
394
+ }
395
+
396
+ throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
397
+ }
398
+
399
+ /**
400
+ * Evaluates scalars and replaces magic values.
401
+ *
402
+ * @param string $scalar
403
+ *
404
+ * @return string A YAML string
405
+ */
406
+ private static function evaluateScalar($scalar)
407
+ {
408
+ $scalar = trim($scalar);
409
+ $scalarLower = strtolower($scalar);
410
+ switch (true) {
411
+ case 'null' === $scalarLower:
412
+ case '' === $scalar:
413
+ case '~' === $scalar:
414
+ return;
415
+ case 'true' === $scalarLower:
416
+ return true;
417
+ case 'false' === $scalarLower:
418
+ return false;
419
+ // Optimise for returning strings.
420
+ case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]):
421
+ switch (true) {
422
+ case 0 === strpos($scalar, '!str'):
423
+ return (string) substr($scalar, 5);
424
+ case 0 === strpos($scalar, '! '):
425
+ return intval(self::parseScalar(substr($scalar, 2)));
426
+ case 0 === strpos($scalar, '!!php/object:'):
427
+ if (self::$objectSupport) {
428
+ return unserialize(substr($scalar, 13));
429
+ }
430
+
431
+ if (self::$exceptionOnInvalidType) {
432
+ throw new ParseException('Object support when parsing a YAML file has been disabled.');
433
+ }
434
+
435
+ return;
436
+ case ctype_digit($scalar):
437
+ $raw = $scalar;
438
+ $cast = intval($scalar);
439
+
440
+ return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
441
+ case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
442
+ $raw = $scalar;
443
+ $cast = intval($scalar);
444
+
445
+ return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
446
+ case is_numeric($scalar):
447
+ return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
448
+ case '.inf' === $scalarLower:
449
+ case '.nan' === $scalarLower:
450
+ return -log(0);
451
+ case '-.inf' === $scalarLower:
452
+ return log(0);
453
+ case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
454
+ return floatval(str_replace(',', '', $scalar));
455
+ case preg_match(self::getTimestampRegex(), $scalar):
456
+ return strtotime($scalar);
457
+ }
458
+ default:
459
+ return (string) $scalar;
460
+ }
461
+ }
462
+
463
+ /**
464
+ * Gets a regex that matches a YAML date.
465
+ *
466
+ * @return string The regular expression
467
+ *
468
+ * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
469
+ */
470
+ private static function getTimestampRegex()
471
+ {
472
+ return <<<EOF
473
+ ~^
474
+ (?P<year>[0-9][0-9][0-9][0-9])
475
+ -(?P<month>[0-9][0-9]?)
476
+ -(?P<day>[0-9][0-9]?)
477
+ (?:(?:[Tt]|[ \t]+)
478
+ (?P<hour>[0-9][0-9]?)
479
+ :(?P<minute>[0-9][0-9])
480
+ :(?P<second>[0-9][0-9])
481
+ (?:\.(?P<fraction>[0-9]*))?
482
+ (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
483
+ (?::(?P<tz_minute>[0-9][0-9]))?))?)?
484
+ $~x
485
+ EOF;
486
+ }
487
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2004-2014 Fabien Potencier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is furnished
8
+ to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Parser.php ADDED
@@ -0,0 +1,655 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml;
13
+
14
+ use Symfony\Component\Yaml\Exception\ParseException;
15
+
16
+ /**
17
+ * Parser parses YAML strings to convert them to PHP arrays.
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Parser
22
+ {
23
+ const FOLDED_SCALAR_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
24
+
25
+ private $offset = 0;
26
+ private $lines = array();
27
+ private $currentLineNb = -1;
28
+ private $currentLine = '';
29
+ private $refs = array();
30
+
31
+ /**
32
+ * Constructor
33
+ *
34
+ * @param int $offset The offset of YAML document (used for line numbers in error messages)
35
+ */
36
+ public function __construct($offset = 0)
37
+ {
38
+ $this->offset = $offset;
39
+ }
40
+
41
+ /**
42
+ * Parses a YAML string to a PHP value.
43
+ *
44
+ * @param string $value A YAML string
45
+ * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
46
+ * @param bool $objectSupport true if object support is enabled, false otherwise
47
+ *
48
+ * @return mixed A PHP value
49
+ *
50
+ * @throws ParseException If the YAML is not valid
51
+ */
52
+ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = false)
53
+ {
54
+ $this->currentLineNb = -1;
55
+ $this->currentLine = '';
56
+ $this->lines = explode("\n", $this->cleanup($value));
57
+
58
+ if (!preg_match('//u', $value)) {
59
+ throw new ParseException('The YAML value does not appear to be valid UTF-8.');
60
+ }
61
+
62
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
63
+ $mbEncoding = mb_internal_encoding();
64
+ mb_internal_encoding('UTF-8');
65
+ }
66
+
67
+ $data = array();
68
+ $context = null;
69
+ while ($this->moveToNextLine()) {
70
+ if ($this->isCurrentLineEmpty()) {
71
+ continue;
72
+ }
73
+
74
+ // tab?
75
+ if ("\t" === $this->currentLine[0]) {
76
+ throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
77
+ }
78
+
79
+ $isRef = $isInPlace = $isProcessed = false;
80
+ if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
81
+ if ($context && 'mapping' == $context) {
82
+ throw new ParseException('You cannot define a sequence item when in a mapping');
83
+ }
84
+ $context = 'sequence';
85
+
86
+ if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
87
+ $isRef = $matches['ref'];
88
+ $values['value'] = $matches['value'];
89
+ }
90
+
91
+ // array
92
+ if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
93
+ $c = $this->getRealCurrentLineNb() + 1;
94
+ $parser = new Parser($c);
95
+ $parser->refs =& $this->refs;
96
+ $data[] = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport);
97
+ } else {
98
+ if (isset($values['leadspaces'])
99
+ && ' ' == $values['leadspaces']
100
+ && preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
101
+ ) {
102
+ // this is a compact notation element, add to next block and parse
103
+ $c = $this->getRealCurrentLineNb();
104
+ $parser = new Parser($c);
105
+ $parser->refs =& $this->refs;
106
+
107
+ $block = $values['value'];
108
+ if ($this->isNextLineIndented()) {
109
+ $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + 2);
110
+ }
111
+
112
+ $data[] = $parser->parse($block, $exceptionOnInvalidType, $objectSupport);
113
+ } else {
114
+ $data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport);
115
+ }
116
+ }
117
+ } elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values) && false === strpos($values['key'],' #')) {
118
+ if ($context && 'sequence' == $context) {
119
+ throw new ParseException('You cannot define a mapping item when in a sequence');
120
+ }
121
+ $context = 'mapping';
122
+
123
+ // force correct settings
124
+ Inline::parse(null, $exceptionOnInvalidType, $objectSupport);
125
+ try {
126
+ $key = Inline::parseScalar($values['key']);
127
+ } catch (ParseException $e) {
128
+ $e->setParsedLine($this->getRealCurrentLineNb() + 1);
129
+ $e->setSnippet($this->currentLine);
130
+
131
+ throw $e;
132
+ }
133
+
134
+ if ('<<' === $key) {
135
+ if (isset($values['value']) && 0 === strpos($values['value'], '*')) {
136
+ $isInPlace = substr($values['value'], 1);
137
+ if (!array_key_exists($isInPlace, $this->refs)) {
138
+ throw new ParseException(sprintf('Reference "%s" does not exist.', $isInPlace), $this->getRealCurrentLineNb() + 1, $this->currentLine);
139
+ }
140
+ } else {
141
+ if (isset($values['value']) && $values['value'] !== '') {
142
+ $value = $values['value'];
143
+ } else {
144
+ $value = $this->getNextEmbedBlock();
145
+ }
146
+ $c = $this->getRealCurrentLineNb() + 1;
147
+ $parser = new Parser($c);
148
+ $parser->refs =& $this->refs;
149
+ $parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport);
150
+
151
+ $merged = array();
152
+ if (!is_array($parsed)) {
153
+ throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
154
+ } elseif (isset($parsed[0])) {
155
+ // Numeric array, merge individual elements
156
+ foreach (array_reverse($parsed) as $parsedItem) {
157
+ if (!is_array($parsedItem)) {
158
+ throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem);
159
+ }
160
+ $merged = array_merge($parsedItem, $merged);
161
+ }
162
+ } else {
163
+ // Associative array, merge
164
+ $merged = array_merge($merged, $parsed);
165
+ }
166
+
167
+ $isProcessed = $merged;
168
+ }
169
+ } elseif (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
170
+ $isRef = $matches['ref'];
171
+ $values['value'] = $matches['value'];
172
+ }
173
+
174
+ if ($isProcessed) {
175
+ // Merge keys
176
+ $data = $isProcessed;
177
+ // hash
178
+ } elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
179
+ // if next line is less indented or equal, then it means that the current value is null
180
+ if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) {
181
+ // Spec: Keys MUST be unique; first one wins.
182
+ // Parser cannot abort this mapping earlier, since lines
183
+ // are processed sequentially.
184
+ if (!isset($data[$key])) {
185
+ $data[$key] = null;
186
+ }
187
+ } else {
188
+ $c = $this->getRealCurrentLineNb() + 1;
189
+ $parser = new Parser($c);
190
+ $parser->refs =& $this->refs;
191
+ $value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport);
192
+ // Spec: Keys MUST be unique; first one wins.
193
+ // Parser cannot abort this mapping earlier, since lines
194
+ // are processed sequentially.
195
+ if (!isset($data[$key])) {
196
+ $data[$key] = $value;
197
+ }
198
+ }
199
+ } else {
200
+ if ($isInPlace) {
201
+ $data = $this->refs[$isInPlace];
202
+ } else {
203
+ $value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport);;
204
+ // Spec: Keys MUST be unique; first one wins.
205
+ // Parser cannot abort this mapping earlier, since lines
206
+ // are processed sequentially.
207
+ if (!isset($data[$key])) {
208
+ $data[$key] = $value;
209
+ }
210
+ }
211
+ }
212
+ } else {
213
+ // 1-liner optionally followed by newline
214
+ $lineCount = count($this->lines);
215
+ if (1 === $lineCount || (2 === $lineCount && empty($this->lines[1]))) {
216
+ try {
217
+ $value = Inline::parse($this->lines[0], $exceptionOnInvalidType, $objectSupport);
218
+ } catch (ParseException $e) {
219
+ $e->setParsedLine($this->getRealCurrentLineNb() + 1);
220
+ $e->setSnippet($this->currentLine);
221
+
222
+ throw $e;
223
+ }
224
+
225
+ if (is_array($value)) {
226
+ $first = reset($value);
227
+ if (is_string($first) && 0 === strpos($first, '*')) {
228
+ $data = array();
229
+ foreach ($value as $alias) {
230
+ $data[] = $this->refs[substr($alias, 1)];
231
+ }
232
+ $value = $data;
233
+ }
234
+ }
235
+
236
+ if (isset($mbEncoding)) {
237
+ mb_internal_encoding($mbEncoding);
238
+ }
239
+
240
+ return $value;
241
+ }
242
+
243
+ switch (preg_last_error()) {
244
+ case PREG_INTERNAL_ERROR:
245
+ $error = 'Internal PCRE error.';
246
+ break;
247
+ case PREG_BACKTRACK_LIMIT_ERROR:
248
+ $error = 'pcre.backtrack_limit reached.';
249
+ break;
250
+ case PREG_RECURSION_LIMIT_ERROR:
251
+ $error = 'pcre.recursion_limit reached.';
252
+ break;
253
+ case PREG_BAD_UTF8_ERROR:
254
+ $error = 'Malformed UTF-8 data.';
255
+ break;
256
+ case PREG_BAD_UTF8_OFFSET_ERROR:
257
+ $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.';
258
+ break;
259
+ default:
260
+ $error = 'Unable to parse.';
261
+ }
262
+
263
+ throw new ParseException($error, $this->getRealCurrentLineNb() + 1, $this->currentLine);
264
+ }
265
+
266
+ if ($isRef) {
267
+ $this->refs[$isRef] = end($data);
268
+ }
269
+ }
270
+
271
+ if (isset($mbEncoding)) {
272
+ mb_internal_encoding($mbEncoding);
273
+ }
274
+
275
+ return empty($data) ? null : $data;
276
+ }
277
+
278
+ /**
279
+ * Returns the current line number (takes the offset into account).
280
+ *
281
+ * @return int The current line number
282
+ */
283
+ private function getRealCurrentLineNb()
284
+ {
285
+ return $this->currentLineNb + $this->offset;
286
+ }
287
+
288
+ /**
289
+ * Returns the current line indentation.
290
+ *
291
+ * @return int The current line indentation
292
+ */
293
+ private function getCurrentLineIndentation()
294
+ {
295
+ return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
296
+ }
297
+
298
+ /**
299
+ * Returns the next embed block of YAML.
300
+ *
301
+ * @param int $indentation The indent level at which the block is to be read, or null for default
302
+ *
303
+ * @return string A YAML string
304
+ *
305
+ * @throws ParseException When indentation problem are detected
306
+ */
307
+ private function getNextEmbedBlock($indentation = null)
308
+ {
309
+ $this->moveToNextLine();
310
+
311
+ if (null === $indentation) {
312
+ $newIndent = $this->getCurrentLineIndentation();
313
+
314
+ $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem($this->currentLine);
315
+
316
+ if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) {
317
+ throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
318
+ }
319
+ } else {
320
+ $newIndent = $indentation;
321
+ }
322
+
323
+ $data = array(substr($this->currentLine, $newIndent));
324
+
325
+ $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem($this->currentLine);
326
+
327
+ // Comments must not be removed inside a string block (ie. after a line ending with "|")
328
+ $removeCommentsPattern = '~'.self::FOLDED_SCALAR_PATTERN.'$~';
329
+ $removeComments = !preg_match($removeCommentsPattern, $this->currentLine);
330
+
331
+ while ($this->moveToNextLine()) {
332
+ $indent = $this->getCurrentLineIndentation();
333
+
334
+ if ($indent === $newIndent) {
335
+ $removeComments = !preg_match($removeCommentsPattern, $this->currentLine);
336
+ }
337
+
338
+ if ($isItUnindentedCollection && !$this->isStringUnIndentedCollectionItem($this->currentLine)) {
339
+ $this->moveToPreviousLine();
340
+ break;
341
+ }
342
+
343
+ if ($this->isCurrentLineBlank()) {
344
+ $data[] = substr($this->currentLine, $newIndent);
345
+ continue;
346
+ }
347
+
348
+ if ($removeComments && $this->isCurrentLineComment()) {
349
+ continue;
350
+ }
351
+
352
+ if ($indent >= $newIndent) {
353
+ $data[] = substr($this->currentLine, $newIndent);
354
+ } elseif (0 == $indent) {
355
+ $this->moveToPreviousLine();
356
+
357
+ break;
358
+ } else {
359
+ throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
360
+ }
361
+ }
362
+
363
+ return implode("\n", $data);
364
+ }
365
+
366
+ /**
367
+ * Moves the parser to the next line.
368
+ *
369
+ * @return bool
370
+ */
371
+ private function moveToNextLine()
372
+ {
373
+ if ($this->currentLineNb >= count($this->lines) - 1) {
374
+ return false;
375
+ }
376
+
377
+ $this->currentLine = $this->lines[++$this->currentLineNb];
378
+
379
+ return true;
380
+ }
381
+
382
+ /**
383
+ * Moves the parser to the previous line.
384
+ */
385
+ private function moveToPreviousLine()
386
+ {
387
+ $this->currentLine = $this->lines[--$this->currentLineNb];
388
+ }
389
+
390
+ /**
391
+ * Parses a YAML value.
392
+ *
393
+ * @param string $value A YAML value
394
+ * @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise
395
+ * @param bool $objectSupport True if object support is enabled, false otherwise
396
+ *
397
+ * @return mixed A PHP value
398
+ *
399
+ * @throws ParseException When reference does not exist
400
+ */
401
+ private function parseValue($value, $exceptionOnInvalidType, $objectSupport)
402
+ {
403
+ if (0 === strpos($value, '*')) {
404
+ if (false !== $pos = strpos($value, '#')) {
405
+ $value = substr($value, 1, $pos - 2);
406
+ } else {
407
+ $value = substr($value, 1);
408
+ }
409
+
410
+ if (!array_key_exists($value, $this->refs)) {
411
+ throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine);
412
+ }
413
+
414
+ return $this->refs[$value];
415
+ }
416
+
417
+ if (preg_match('/^'.self::FOLDED_SCALAR_PATTERN.'$/', $value, $matches)) {
418
+ $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
419
+
420
+ return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
421
+ }
422
+
423
+ try {
424
+ return Inline::parse($value, $exceptionOnInvalidType, $objectSupport);
425
+ } catch (ParseException $e) {
426
+ $e->setParsedLine($this->getRealCurrentLineNb() + 1);
427
+ $e->setSnippet($this->currentLine);
428
+
429
+ throw $e;
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Parses a folded scalar.
435
+ *
436
+ * @param string $separator The separator that was used to begin this folded scalar (| or >)
437
+ * @param string $indicator The indicator that was used to begin this folded scalar (+ or -)
438
+ * @param int $indentation The indentation that was used to begin this folded scalar
439
+ *
440
+ * @return string The text value
441
+ */
442
+ private function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
443
+ {
444
+ $notEOF = $this->moveToNextLine();
445
+ if (!$notEOF) {
446
+ return '';
447
+ }
448
+
449
+ $isCurrentLineBlank = $this->isCurrentLineBlank();
450
+ $text = '';
451
+
452
+ // leading blank lines are consumed before determining indentation
453
+ while ($notEOF && $isCurrentLineBlank) {
454
+ // newline only if not EOF
455
+ if ($notEOF = $this->moveToNextLine()) {
456
+ $text .= "\n";
457
+ $isCurrentLineBlank = $this->isCurrentLineBlank();
458
+ }
459
+ }
460
+
461
+ // determine indentation if not specified
462
+ if (0 === $indentation) {
463
+ if (preg_match('/^ +/', $this->currentLine, $matches)) {
464
+ $indentation = strlen($matches[0]);
465
+ }
466
+ }
467
+
468
+ if ($indentation > 0) {
469
+ $pattern = sprintf('/^ {%d}(.*)$/', $indentation);
470
+
471
+ while (
472
+ $notEOF && (
473
+ $isCurrentLineBlank ||
474
+ preg_match($pattern, $this->currentLine, $matches)
475
+ )
476
+ ) {
477
+ if ($isCurrentLineBlank) {
478
+ $text .= substr($this->currentLine, $indentation);
479
+ } else {
480
+ $text .= $matches[1];
481
+ }
482
+
483
+ // newline only if not EOF
484
+ if ($notEOF = $this->moveToNextLine()) {
485
+ $text .= "\n";
486
+ $isCurrentLineBlank = $this->isCurrentLineBlank();
487
+ }
488
+ }
489
+ } elseif ($notEOF) {
490
+ $text .= "\n";
491
+ }
492
+
493
+ if ($notEOF) {
494
+ $this->moveToPreviousLine();
495
+ }
496
+
497
+ // replace all non-trailing single newlines with spaces in folded blocks
498
+ if ('>' === $separator) {
499
+ preg_match('/(\n*)$/', $text, $matches);
500
+ $text = preg_replace('/(?<!\n)\n(?!\n)/', ' ', rtrim($text, "\n"));
501
+ $text .= $matches[1];
502
+ }
503
+
504
+ // deal with trailing newlines as indicated
505
+ if ('' === $indicator) {
506
+ $text = preg_replace('/\n+$/s', "\n", $text);
507
+ } elseif ('-' === $indicator) {
508
+ $text = preg_replace('/\n+$/s', '', $text);
509
+ }
510
+
511
+ return $text;
512
+ }
513
+
514
+ /**
515
+ * Returns true if the next line is indented.
516
+ *
517
+ * @return bool Returns true if the next line is indented, false otherwise
518
+ */
519
+ private function isNextLineIndented()
520
+ {
521
+ $currentIndentation = $this->getCurrentLineIndentation();
522
+ $EOF = !$this->moveToNextLine();
523
+
524
+ while (!$EOF && $this->isCurrentLineEmpty()) {
525
+ $EOF = !$this->moveToNextLine();
526
+ }
527
+
528
+ if ($EOF) {
529
+ return false;
530
+ }
531
+
532
+ $ret = false;
533
+ if ($this->getCurrentLineIndentation() > $currentIndentation) {
534
+ $ret = true;
535
+ }
536
+
537
+ $this->moveToPreviousLine();
538
+
539
+ return $ret;
540
+ }
541
+
542
+ /**
543
+ * Returns true if the current line is blank or if it is a comment line.
544
+ *
545
+ * @return bool Returns true if the current line is empty or if it is a comment line, false otherwise
546
+ */
547
+ private function isCurrentLineEmpty()
548
+ {
549
+ return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
550
+ }
551
+
552
+ /**
553
+ * Returns true if the current line is blank.
554
+ *
555
+ * @return bool Returns true if the current line is blank, false otherwise
556
+ */
557
+ private function isCurrentLineBlank()
558
+ {
559
+ return '' == trim($this->currentLine, ' ');
560
+ }
561
+
562
+ /**
563
+ * Returns true if the current line is a comment line.
564
+ *
565
+ * @return bool Returns true if the current line is a comment line, false otherwise
566
+ */
567
+ private function isCurrentLineComment()
568
+ {
569
+ //checking explicitly the first char of the trim is faster than loops or strpos
570
+ $ltrimmedLine = ltrim($this->currentLine, ' ');
571
+
572
+ return $ltrimmedLine[0] === '#';
573
+ }
574
+
575
+ /**
576
+ * Cleanups a YAML string to be parsed.
577
+ *
578
+ * @param string $value The input YAML string
579
+ *
580
+ * @return string A cleaned up YAML string
581
+ */
582
+ private function cleanup($value)
583
+ {
584
+ $value = str_replace(array("\r\n", "\r"), "\n", $value);
585
+
586
+ // strip YAML header
587
+ $count = 0;
588
+ $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#su', '', $value, -1, $count);
589
+ $this->offset += $count;
590
+
591
+ // remove leading comments
592
+ $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
593
+ if ($count == 1) {
594
+ // items have been removed, update the offset
595
+ $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
596
+ $value = $trimmedValue;
597
+ }
598
+
599
+ // remove start of the document marker (---)
600
+ $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
601
+ if ($count == 1) {
602
+ // items have been removed, update the offset
603
+ $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
604
+ $value = $trimmedValue;
605
+
606
+ // remove end of the document marker (...)
607
+ $value = preg_replace('#\.\.\.\s*$#s', '', $value);
608
+ }
609
+
610
+ return $value;
611
+ }
612
+
613
+ /**
614
+ * Returns true if the next line starts unindented collection
615
+ *
616
+ * @return bool Returns true if the next line starts unindented collection, false otherwise
617
+ */
618
+ private function isNextLineUnIndentedCollection()
619
+ {
620
+ $currentIndentation = $this->getCurrentLineIndentation();
621
+ $notEOF = $this->moveToNextLine();
622
+
623
+ while ($notEOF && $this->isCurrentLineEmpty()) {
624
+ $notEOF = $this->moveToNextLine();
625
+ }
626
+
627
+ if (false === $notEOF) {
628
+ return false;
629
+ }
630
+
631
+ $ret = false;
632
+ if (
633
+ $this->getCurrentLineIndentation() == $currentIndentation
634
+ &&
635
+ $this->isStringUnIndentedCollectionItem($this->currentLine)
636
+ ) {
637
+ $ret = true;
638
+ }
639
+
640
+ $this->moveToPreviousLine();
641
+
642
+ return $ret;
643
+ }
644
+
645
+ /**
646
+ * Returns true if the string is un-indented collection item
647
+ *
648
+ * @return bool Returns true if the string is un-indented collection item, false otherwise
649
+ */
650
+ private function isStringUnIndentedCollectionItem()
651
+ {
652
+ return (0 === strpos($this->currentLine, '- '));
653
+ }
654
+
655
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/README.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Yaml Component
2
+ ==============
3
+
4
+ YAML implements most of the YAML 1.2 specification.
5
+
6
+ use Symfony\Component\Yaml\Yaml;
7
+
8
+ $array = Yaml::parse($file);
9
+
10
+ print Yaml::dump($array);
11
+
12
+ Resources
13
+ ---------
14
+
15
+ You can run the unit tests with the following command:
16
+
17
+ $ cd path/to/Symfony/Component/Yaml/
18
+ $ composer.phar install
19
+ $ phpunit
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/DumperTest.php ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Tests;
13
+
14
+ use Symfony\Component\Yaml\Yaml;
15
+ use Symfony\Component\Yaml\Parser;
16
+ use Symfony\Component\Yaml\Dumper;
17
+
18
+ class DumperTest extends \PHPUnit_Framework_TestCase
19
+ {
20
+ protected $parser;
21
+ protected $dumper;
22
+ protected $path;
23
+
24
+ protected $array = array(
25
+ '' => 'bar',
26
+ 'foo' => '#bar',
27
+ 'foo\'bar' => array(),
28
+ 'bar' => array(1, 'foo'),
29
+ 'foobar' => array(
30
+ 'foo' => 'bar',
31
+ 'bar' => array(1, 'foo'),
32
+ 'foobar' => array(
33
+ 'foo' => 'bar',
34
+ 'bar' => array(1, 'foo'),
35
+ ),
36
+ ),
37
+ );
38
+
39
+ protected function setUp()
40
+ {
41
+ $this->parser = new Parser();
42
+ $this->dumper = new Dumper();
43
+ $this->path = __DIR__.'/Fixtures';
44
+ }
45
+
46
+ protected function tearDown()
47
+ {
48
+ $this->parser = null;
49
+ $this->dumper = null;
50
+ $this->path = null;
51
+ $this->array = null;
52
+ }
53
+
54
+ public function testSetIndentation()
55
+ {
56
+ $this->dumper->setIndentation(7);
57
+
58
+ $expected = <<<EOF
59
+ '': bar
60
+ foo: '#bar'
61
+ 'foo''bar': { }
62
+ bar:
63
+ - 1
64
+ - foo
65
+ foobar:
66
+ foo: bar
67
+ bar:
68
+ - 1
69
+ - foo
70
+ foobar:
71
+ foo: bar
72
+ bar:
73
+ - 1
74
+ - foo
75
+
76
+ EOF;
77
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 4, 0));
78
+ }
79
+
80
+ public function testSpecifications()
81
+ {
82
+ $files = $this->parser->parse(file_get_contents($this->path.'/index.yml'));
83
+ foreach ($files as $file) {
84
+ $yamls = file_get_contents($this->path.'/'.$file.'.yml');
85
+
86
+ // split YAMLs documents
87
+ foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) {
88
+ if (!$yaml) {
89
+ continue;
90
+ }
91
+
92
+ $test = $this->parser->parse($yaml);
93
+ if (isset($test['dump_skip']) && $test['dump_skip']) {
94
+ continue;
95
+ } elseif (isset($test['todo']) && $test['todo']) {
96
+ // TODO
97
+ } else {
98
+ eval('$expected = '.trim($test['php']).';');
99
+
100
+ $this->assertEquals($expected, $this->parser->parse($this->dumper->dump($expected, 10)), $test['test']);
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ public function testInlineLevel()
107
+ {
108
+ $expected = <<<EOF
109
+ { '': bar, foo: '#bar', 'foo''bar': { }, bar: [1, foo], foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } }
110
+ EOF;
111
+ $this->assertEquals($expected, $this->dumper->dump($this->array, -10), '->dump() takes an inline level argument');
112
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 0), '->dump() takes an inline level argument');
113
+
114
+ $expected = <<<EOF
115
+ '': bar
116
+ foo: '#bar'
117
+ 'foo''bar': { }
118
+ bar: [1, foo]
119
+ foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } }
120
+
121
+ EOF;
122
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 1), '->dump() takes an inline level argument');
123
+
124
+ $expected = <<<EOF
125
+ '': bar
126
+ foo: '#bar'
127
+ 'foo''bar': { }
128
+ bar:
129
+ - 1
130
+ - foo
131
+ foobar:
132
+ foo: bar
133
+ bar: [1, foo]
134
+ foobar: { foo: bar, bar: [1, foo] }
135
+
136
+ EOF;
137
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 2), '->dump() takes an inline level argument');
138
+
139
+ $expected = <<<EOF
140
+ '': bar
141
+ foo: '#bar'
142
+ 'foo''bar': { }
143
+ bar:
144
+ - 1
145
+ - foo
146
+ foobar:
147
+ foo: bar
148
+ bar:
149
+ - 1
150
+ - foo
151
+ foobar:
152
+ foo: bar
153
+ bar: [1, foo]
154
+
155
+ EOF;
156
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 3), '->dump() takes an inline level argument');
157
+
158
+ $expected = <<<EOF
159
+ '': bar
160
+ foo: '#bar'
161
+ 'foo''bar': { }
162
+ bar:
163
+ - 1
164
+ - foo
165
+ foobar:
166
+ foo: bar
167
+ bar:
168
+ - 1
169
+ - foo
170
+ foobar:
171
+ foo: bar
172
+ bar:
173
+ - 1
174
+ - foo
175
+
176
+ EOF;
177
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 4), '->dump() takes an inline level argument');
178
+ $this->assertEquals($expected, $this->dumper->dump($this->array, 10), '->dump() takes an inline level argument');
179
+ }
180
+
181
+ public function testObjectSupportEnabled()
182
+ {
183
+ $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, false, true);
184
+
185
+ $this->assertEquals('{ foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects');
186
+ }
187
+
188
+ public function testObjectSupportDisabledButNoExceptions()
189
+ {
190
+ $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1));
191
+
192
+ $this->assertEquals('{ foo: null, bar: 1 }', $dump, '->dump() does not dump objects when disabled');
193
+ }
194
+
195
+ /**
196
+ * @expectedException \Symfony\Component\Yaml\Exception\DumpException
197
+ */
198
+ public function testObjectSupportDisabledWithExceptions()
199
+ {
200
+ $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, true, false);
201
+ }
202
+ }
203
+
204
+ class A
205
+ {
206
+ public $a = 'foo';
207
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsAnchorAlias.yml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Simple Alias Example
3
+ brief: >
4
+ If you need to refer to the same item of data twice,
5
+ you can give that item an alias. The alias is a plain
6
+ string, starting with an ampersand. The item may then
7
+ be referred to by the alias throughout your document
8
+ by using an asterisk before the name of the alias.
9
+ This is called an anchor.
10
+ yaml: |
11
+ - &showell Steve
12
+ - Clark
13
+ - Brian
14
+ - Oren
15
+ - *showell
16
+ php: |
17
+ array('Steve', 'Clark', 'Brian', 'Oren', 'Steve')
18
+
19
+ ---
20
+ test: Alias of a Mapping
21
+ brief: >
22
+ An alias can be used on any item of data, including
23
+ sequences, mappings, and other complex data types.
24
+ yaml: |
25
+ - &hello
26
+ Meat: pork
27
+ Starch: potato
28
+ - banana
29
+ - *hello
30
+ php: |
31
+ array(array('Meat'=>'pork', 'Starch'=>'potato'), 'banana', array('Meat'=>'pork', 'Starch'=>'potato'))
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsBasicTests.yml ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Simple Sequence
3
+ brief: |
4
+ You can specify a list in YAML by placing each
5
+ member of the list on a new line with an opening
6
+ dash. These lists are called sequences.
7
+ yaml: |
8
+ - apple
9
+ - banana
10
+ - carrot
11
+ php: |
12
+ array('apple', 'banana', 'carrot')
13
+ ---
14
+ test: Nested Sequences
15
+ brief: |
16
+ You can include a sequence within another
17
+ sequence by giving the sequence an empty
18
+ dash, followed by an indented list.
19
+ yaml: |
20
+ -
21
+ - foo
22
+ - bar
23
+ - baz
24
+ php: |
25
+ array(array('foo', 'bar', 'baz'))
26
+ ---
27
+ test: Mixed Sequences
28
+ brief: |
29
+ Sequences can contain any YAML data,
30
+ including strings and other sequences.
31
+ yaml: |
32
+ - apple
33
+ -
34
+ - foo
35
+ - bar
36
+ - x123
37
+ - banana
38
+ - carrot
39
+ php: |
40
+ array('apple', array('foo', 'bar', 'x123'), 'banana', 'carrot')
41
+ ---
42
+ test: Deeply Nested Sequences
43
+ brief: |
44
+ Sequences can be nested even deeper, with each
45
+ level of indentation representing a level of
46
+ depth.
47
+ yaml: |
48
+ -
49
+ -
50
+ - uno
51
+ - dos
52
+ php: |
53
+ array(array(array('uno', 'dos')))
54
+ ---
55
+ test: Simple Mapping
56
+ brief: |
57
+ You can add a keyed list (also known as a dictionary or
58
+ hash) to your document by placing each member of the
59
+ list on a new line, with a colon separating the key
60
+ from its value. In YAML, this type of list is called
61
+ a mapping.
62
+ yaml: |
63
+ foo: whatever
64
+ bar: stuff
65
+ php: |
66
+ array('foo' => 'whatever', 'bar' => 'stuff')
67
+ ---
68
+ test: Sequence in a Mapping
69
+ brief: |
70
+ A value in a mapping can be a sequence.
71
+ yaml: |
72
+ foo: whatever
73
+ bar:
74
+ - uno
75
+ - dos
76
+ php: |
77
+ array('foo' => 'whatever', 'bar' => array('uno', 'dos'))
78
+ ---
79
+ test: Nested Mappings
80
+ brief: |
81
+ A value in a mapping can be another mapping.
82
+ yaml: |
83
+ foo: whatever
84
+ bar:
85
+ fruit: apple
86
+ name: steve
87
+ sport: baseball
88
+ php: |
89
+ array(
90
+ 'foo' => 'whatever',
91
+ 'bar' => array(
92
+ 'fruit' => 'apple',
93
+ 'name' => 'steve',
94
+ 'sport' => 'baseball'
95
+ )
96
+ )
97
+ ---
98
+ test: Mixed Mapping
99
+ brief: |
100
+ A mapping can contain any assortment
101
+ of mappings and sequences as values.
102
+ yaml: |
103
+ foo: whatever
104
+ bar:
105
+ -
106
+ fruit: apple
107
+ name: steve
108
+ sport: baseball
109
+ - more
110
+ -
111
+ python: rocks
112
+ perl: papers
113
+ ruby: scissorses
114
+ php: |
115
+ array(
116
+ 'foo' => 'whatever',
117
+ 'bar' => array(
118
+ array(
119
+ 'fruit' => 'apple',
120
+ 'name' => 'steve',
121
+ 'sport' => 'baseball'
122
+ ),
123
+ 'more',
124
+ array(
125
+ 'python' => 'rocks',
126
+ 'perl' => 'papers',
127
+ 'ruby' => 'scissorses'
128
+ )
129
+ )
130
+ )
131
+ ---
132
+ test: Mapping-in-Sequence Shortcut
133
+ todo: true
134
+ brief: |
135
+ If you are adding a mapping to a sequence, you
136
+ can place the mapping on the same line as the
137
+ dash as a shortcut.
138
+ yaml: |
139
+ - work on YAML.py:
140
+ - work on Store
141
+ php: |
142
+ array(array('work on YAML.py' => array('work on Store')))
143
+ ---
144
+ test: Sequence-in-Mapping Shortcut
145
+ todo: true
146
+ brief: |
147
+ The dash in a sequence counts as indentation, so
148
+ you can add a sequence inside of a mapping without
149
+ needing spaces as indentation.
150
+ yaml: |
151
+ allow:
152
+ - 'localhost'
153
+ - '%.sourceforge.net'
154
+ - '%.freepan.org'
155
+ php: |
156
+ array('allow' => array('localhost', '%.sourceforge.net', '%.freepan.org'))
157
+ ---
158
+ todo: true
159
+ test: Merge key
160
+ brief: |
161
+ A merge key ('<<') can be used in a mapping to insert other mappings. If
162
+ the value associated with the merge key is a mapping, each of its key/value
163
+ pairs is inserted into the current mapping.
164
+ yaml: |
165
+ mapping:
166
+ name: Joe
167
+ job: Accountant
168
+ <<:
169
+ age: 38
170
+ php: |
171
+ array(
172
+ 'mapping' =>
173
+ array(
174
+ 'name' => 'Joe',
175
+ 'job' => 'Accountant',
176
+ 'age' => 38
177
+ )
178
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsBlockMapping.yml ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ test: One Element Mapping
3
+ brief: |
4
+ A mapping with one key/value pair
5
+ yaml: |
6
+ foo: bar
7
+ php: |
8
+ array('foo' => 'bar')
9
+ ---
10
+ test: Multi Element Mapping
11
+ brief: |
12
+ More than one key/value pair
13
+ yaml: |
14
+ red: baron
15
+ white: walls
16
+ blue: berries
17
+ php: |
18
+ array(
19
+ 'red' => 'baron',
20
+ 'white' => 'walls',
21
+ 'blue' => 'berries',
22
+ )
23
+ ---
24
+ test: Values aligned
25
+ brief: |
26
+ Often times human editors of documents will align the values even
27
+ though YAML emitters generally don't.
28
+ yaml: |
29
+ red: baron
30
+ white: walls
31
+ blue: berries
32
+ php: |
33
+ array(
34
+ 'red' => 'baron',
35
+ 'white' => 'walls',
36
+ 'blue' => 'berries',
37
+ )
38
+ ---
39
+ test: Colons aligned
40
+ brief: |
41
+ Spaces can come before the ': ' key/value separator.
42
+ yaml: |
43
+ red : baron
44
+ white : walls
45
+ blue : berries
46
+ php: |
47
+ array(
48
+ 'red' => 'baron',
49
+ 'white' => 'walls',
50
+ 'blue' => 'berries',
51
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsDocumentSeparator.yml ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Trailing Document Separator
3
+ todo: true
4
+ brief: >
5
+ You can separate YAML documents
6
+ with a string of three dashes.
7
+ yaml: |
8
+ - foo: 1
9
+ bar: 2
10
+ ---
11
+ more: stuff
12
+ python: |
13
+ [
14
+ [ { 'foo': 1, 'bar': 2 } ],
15
+ { 'more': 'stuff' }
16
+ ]
17
+ ruby: |
18
+ [ { 'foo' => 1, 'bar' => 2 } ]
19
+
20
+ ---
21
+ test: Leading Document Separator
22
+ todo: true
23
+ brief: >
24
+ You can explicity give an opening
25
+ document separator to your YAML stream.
26
+ yaml: |
27
+ ---
28
+ - foo: 1
29
+ bar: 2
30
+ ---
31
+ more: stuff
32
+ python: |
33
+ [
34
+ [ {'foo': 1, 'bar': 2}],
35
+ {'more': 'stuff'}
36
+ ]
37
+ ruby: |
38
+ [ { 'foo' => 1, 'bar' => 2 } ]
39
+
40
+ ---
41
+ test: YAML Header
42
+ todo: true
43
+ brief: >
44
+ The opening separator can contain directives
45
+ to the YAML parser, such as the version
46
+ number.
47
+ yaml: |
48
+ --- %YAML:1.0
49
+ foo: 1
50
+ bar: 2
51
+ php: |
52
+ array('foo' => 1, 'bar' => 2)
53
+ documents: 1
54
+
55
+ ---
56
+ test: Red Herring Document Separator
57
+ brief: >
58
+ Separators included in blocks or strings
59
+ are treated as blocks or strings, as the
60
+ document separator should have no indentation
61
+ preceding it.
62
+ yaml: |
63
+ foo: |
64
+ ---
65
+ php: |
66
+ array('foo' => "---\n")
67
+
68
+ ---
69
+ test: Multiple Document Separators in Block
70
+ brief: >
71
+ This technique allows you to embed other YAML
72
+ documents within literal blocks.
73
+ yaml: |
74
+ foo: |
75
+ ---
76
+ foo: bar
77
+ ---
78
+ yo: baz
79
+ bar: |
80
+ fooness
81
+ php: |
82
+ array(
83
+ 'foo' => "---\nfoo: bar\n---\nyo: baz\n",
84
+ 'bar' => "fooness\n"
85
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsErrorTests.yml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ test: Missing value for hash item
3
+ todo: true
4
+ brief: |
5
+ Third item in this hash doesn't have a value
6
+ yaml: |
7
+ okay: value
8
+ also okay: ~
9
+ causes error because no value specified
10
+ last key: value okay here too
11
+ python-error: causes error because no value specified
12
+
13
+ ---
14
+ test: Not indenting enough
15
+ brief: |
16
+ There was a bug in PyYaml where it was off by one
17
+ in the indentation check. It was allowing the YAML
18
+ below.
19
+ # This is actually valid YAML now. Someone should tell showell.
20
+ yaml: |
21
+ foo:
22
+ firstline: 1
23
+ secondline: 2
24
+ php: |
25
+ array('foo' => null, 'firstline' => 1, 'secondline' => 2)
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsFlowCollections.yml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ test: Simple Inline Array
3
+ brief: >
4
+ Sequences can be contained on a
5
+ single line, using the inline syntax.
6
+ Separate each entry with commas and
7
+ enclose in square brackets.
8
+ yaml: |
9
+ seq: [ a, b, c ]
10
+ php: |
11
+ array('seq' => array('a', 'b', 'c'))
12
+ ---
13
+ test: Simple Inline Hash
14
+ brief: >
15
+ Mapping can also be contained on
16
+ a single line, using the inline
17
+ syntax. Each key-value pair is
18
+ separated by a colon, with a comma
19
+ between each entry in the mapping.
20
+ Enclose with curly braces.
21
+ yaml: |
22
+ hash: { name: Steve, foo: bar }
23
+ php: |
24
+ array('hash' => array('name' => 'Steve', 'foo' => 'bar'))
25
+ ---
26
+ test: Multi-line Inline Collections
27
+ todo: true
28
+ brief: >
29
+ Both inline sequences and inline mappings
30
+ can span multiple lines, provided that you
31
+ indent the additional lines.
32
+ yaml: |
33
+ languages: [ Ruby,
34
+ Perl,
35
+ Python ]
36
+ websites: { YAML: yaml.org,
37
+ Ruby: ruby-lang.org,
38
+ Python: python.org,
39
+ Perl: use.perl.org }
40
+ php: |
41
+ array(
42
+ 'languages' => array('Ruby', 'Perl', 'Python'),
43
+ 'websites' => array(
44
+ 'YAML' => 'yaml.org',
45
+ 'Ruby' => 'ruby-lang.org',
46
+ 'Python' => 'python.org',
47
+ 'Perl' => 'use.perl.org'
48
+ )
49
+ )
50
+ ---
51
+ test: Commas in Values (not in the spec!)
52
+ todo: true
53
+ brief: >
54
+ List items in collections are delimited by commas, but
55
+ there must be a space after each comma. This allows you
56
+ to add numbers without quoting.
57
+ yaml: |
58
+ attendances: [ 45,123, 70,000, 17,222 ]
59
+ php: |
60
+ array('attendances' => array(45123, 70000, 17222))
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsFoldedScalars.yml ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Single ending newline
3
+ brief: >
4
+ A pipe character, followed by an indented
5
+ block of text is treated as a literal
6
+ block, in which newlines are preserved
7
+ throughout the block, including the final
8
+ newline.
9
+ yaml: |
10
+ ---
11
+ this: |
12
+ Foo
13
+ Bar
14
+ php: |
15
+ array('this' => "Foo\nBar\n")
16
+ ---
17
+ test: The '+' indicator
18
+ brief: >
19
+ The '+' indicator says to keep newlines at the end of text
20
+ blocks.
21
+ yaml: |
22
+ normal: |
23
+ extra new lines not kept
24
+
25
+ preserving: |+
26
+ extra new lines are kept
27
+
28
+
29
+ dummy: value
30
+ php: |
31
+ array(
32
+ 'normal' => "extra new lines not kept\n",
33
+ 'preserving' => "extra new lines are kept\n\n\n",
34
+ 'dummy' => 'value'
35
+ )
36
+ ---
37
+ test: Three trailing newlines in literals
38
+ brief: >
39
+ To give you more control over how space
40
+ is preserved in text blocks, YAML has
41
+ the keep '+' and chomp '-' indicators.
42
+ The keep indicator will preserve all
43
+ ending newlines, while the chomp indicator
44
+ will strip all ending newlines.
45
+ yaml: |
46
+ clipped: |
47
+ This has one newline.
48
+
49
+
50
+
51
+ same as "clipped" above: "This has one newline.\n"
52
+
53
+ stripped: |-
54
+ This has no newline.
55
+
56
+
57
+
58
+ same as "stripped" above: "This has no newline."
59
+
60
+ kept: |+
61
+ This has four newlines.
62
+
63
+
64
+
65
+ same as "kept" above: "This has four newlines.\n\n\n\n"
66
+ php: |
67
+ array(
68
+ 'clipped' => "This has one newline.\n",
69
+ 'same as "clipped" above' => "This has one newline.\n",
70
+ 'stripped' => 'This has no newline.',
71
+ 'same as "stripped" above' => 'This has no newline.',
72
+ 'kept' => "This has four newlines.\n\n\n\n",
73
+ 'same as "kept" above' => "This has four newlines.\n\n\n\n"
74
+ )
75
+ ---
76
+ test: Extra trailing newlines with spaces
77
+ todo: true
78
+ brief: >
79
+ Normally, only a single newline is kept
80
+ from the end of a literal block, unless the
81
+ keep '+' character is used in combination
82
+ with the pipe. The following example
83
+ will preserve all ending whitespace
84
+ since the last line of both literal blocks
85
+ contains spaces which extend past the indentation
86
+ level.
87
+ yaml: |
88
+ ---
89
+ this: |
90
+ Foo
91
+
92
+
93
+ kept: |+
94
+ Foo
95
+
96
+
97
+ php: |
98
+ array('this' => "Foo\n\n \n",
99
+ 'kept' => "Foo\n\n \n" )
100
+
101
+ ---
102
+ test: Folded Block in a Sequence
103
+ brief: >
104
+ A greater-then character, followed by an indented
105
+ block of text is treated as a folded block, in
106
+ which lines of text separated by a single newline
107
+ are concatenated as a single line.
108
+ yaml: |
109
+ ---
110
+ - apple
111
+ - banana
112
+ - >
113
+ can't you see
114
+ the beauty of yaml?
115
+ hmm
116
+ - dog
117
+ php: |
118
+ array(
119
+ 'apple',
120
+ 'banana',
121
+ "can't you see the beauty of yaml? hmm\n",
122
+ 'dog'
123
+ )
124
+ ---
125
+ test: Folded Block as a Mapping Value
126
+ brief: >
127
+ Both literal and folded blocks can be
128
+ used in collections, as values in a
129
+ sequence or a mapping.
130
+ yaml: |
131
+ ---
132
+ quote: >
133
+ Mark McGwire's
134
+ year was crippled
135
+ by a knee injury.
136
+ source: espn
137
+ php: |
138
+ array(
139
+ 'quote' => "Mark McGwire's year was crippled by a knee injury.\n",
140
+ 'source' => 'espn'
141
+ )
142
+ ---
143
+ test: Three trailing newlines in folded blocks
144
+ brief: >
145
+ The keep and chomp indicators can also
146
+ be applied to folded blocks.
147
+ yaml: |
148
+ clipped: >
149
+ This has one newline.
150
+
151
+
152
+
153
+ same as "clipped" above: "This has one newline.\n"
154
+
155
+ stripped: >-
156
+ This has no newline.
157
+
158
+
159
+
160
+ same as "stripped" above: "This has no newline."
161
+
162
+ kept: >+
163
+ This has four newlines.
164
+
165
+
166
+
167
+ same as "kept" above: "This has four newlines.\n\n\n\n"
168
+ php: |
169
+ array(
170
+ 'clipped' => "This has one newline.\n",
171
+ 'same as "clipped" above' => "This has one newline.\n",
172
+ 'stripped' => 'This has no newline.',
173
+ 'same as "stripped" above' => 'This has no newline.',
174
+ 'kept' => "This has four newlines.\n\n\n\n",
175
+ 'same as "kept" above' => "This has four newlines.\n\n\n\n"
176
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsNullsAndEmpties.yml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Empty Sequence
3
+ brief: >
4
+ You can represent the empty sequence
5
+ with an empty inline sequence.
6
+ yaml: |
7
+ empty: []
8
+ php: |
9
+ array('empty' => array())
10
+ ---
11
+ test: Empty Mapping
12
+ brief: >
13
+ You can represent the empty mapping
14
+ with an empty inline mapping.
15
+ yaml: |
16
+ empty: {}
17
+ php: |
18
+ array('empty' => array())
19
+ ---
20
+ test: Empty Sequence as Entire Document
21
+ yaml: |
22
+ []
23
+ php: |
24
+ array()
25
+ ---
26
+ test: Empty Mapping as Entire Document
27
+ yaml: |
28
+ {}
29
+ php: |
30
+ array()
31
+ ---
32
+ test: Null as Document
33
+ yaml: |
34
+ ~
35
+ php: |
36
+ null
37
+ ---
38
+ test: Empty String
39
+ brief: >
40
+ You can represent an empty string
41
+ with a pair of quotes.
42
+ yaml: |
43
+ ''
44
+ php: |
45
+ ''
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml ADDED
@@ -0,0 +1,1695 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Sequence of scalars
3
+ spec: 2.1
4
+ yaml: |
5
+ - Mark McGwire
6
+ - Sammy Sosa
7
+ - Ken Griffey
8
+ php: |
9
+ array('Mark McGwire', 'Sammy Sosa', 'Ken Griffey')
10
+ ---
11
+ test: Mapping of scalars to scalars
12
+ spec: 2.2
13
+ yaml: |
14
+ hr: 65
15
+ avg: 0.278
16
+ rbi: 147
17
+ php: |
18
+ array('hr' => 65, 'avg' => 0.278, 'rbi' => 147)
19
+ ---
20
+ test: Mapping of scalars to sequences
21
+ spec: 2.3
22
+ yaml: |
23
+ american:
24
+ - Boston Red Sox
25
+ - Detroit Tigers
26
+ - New York Yankees
27
+ national:
28
+ - New York Mets
29
+ - Chicago Cubs
30
+ - Atlanta Braves
31
+ php: |
32
+ array('american' =>
33
+ array( 'Boston Red Sox', 'Detroit Tigers',
34
+ 'New York Yankees' ),
35
+ 'national' =>
36
+ array( 'New York Mets', 'Chicago Cubs',
37
+ 'Atlanta Braves' )
38
+ )
39
+ ---
40
+ test: Sequence of mappings
41
+ spec: 2.4
42
+ yaml: |
43
+ -
44
+ name: Mark McGwire
45
+ hr: 65
46
+ avg: 0.278
47
+ -
48
+ name: Sammy Sosa
49
+ hr: 63
50
+ avg: 0.288
51
+ php: |
52
+ array(
53
+ array('name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278),
54
+ array('name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288)
55
+ )
56
+ ---
57
+ test: Legacy A5
58
+ todo: true
59
+ spec: legacy_A5
60
+ yaml: |
61
+ ?
62
+ - New York Yankees
63
+ - Atlanta Braves
64
+ :
65
+ - 2001-07-02
66
+ - 2001-08-12
67
+ - 2001-08-14
68
+ ?
69
+ - Detroit Tigers
70
+ - Chicago Cubs
71
+ :
72
+ - 2001-07-23
73
+ perl-busted: >
74
+ YAML.pm will be able to emulate this behavior soon. In this regard
75
+ it may be somewhat more correct than Python's native behaviour which
76
+ can only use tuples as mapping keys. PyYAML will also need to figure
77
+ out some clever way to roundtrip structured keys.
78
+ python: |
79
+ [
80
+ {
81
+ ('New York Yankees', 'Atlanta Braves'):
82
+ [yaml.timestamp('2001-07-02'),
83
+ yaml.timestamp('2001-08-12'),
84
+ yaml.timestamp('2001-08-14')],
85
+ ('Detroit Tigers', 'Chicago Cubs'):
86
+ [yaml.timestamp('2001-07-23')]
87
+ }
88
+ ]
89
+ ruby: |
90
+ {
91
+ [ 'New York Yankees', 'Atlanta Braves' ] =>
92
+ [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ],
93
+ [ 'Detroit Tigers', 'Chicago Cubs' ] =>
94
+ [ Date.new( 2001, 7, 23 ) ]
95
+ }
96
+ syck: |
97
+ struct test_node seq1[] = {
98
+ { T_STR, 0, "New York Yankees" },
99
+ { T_STR, 0, "Atlanta Braves" },
100
+ end_node
101
+ };
102
+ struct test_node seq2[] = {
103
+ { T_STR, 0, "2001-07-02" },
104
+ { T_STR, 0, "2001-08-12" },
105
+ { T_STR, 0, "2001-08-14" },
106
+ end_node
107
+ };
108
+ struct test_node seq3[] = {
109
+ { T_STR, 0, "Detroit Tigers" },
110
+ { T_STR, 0, "Chicago Cubs" },
111
+ end_node
112
+ };
113
+ struct test_node seq4[] = {
114
+ { T_STR, 0, "2001-07-23" },
115
+ end_node
116
+ };
117
+ struct test_node map[] = {
118
+ { T_SEQ, 0, 0, seq1 },
119
+ { T_SEQ, 0, 0, seq2 },
120
+ { T_SEQ, 0, 0, seq3 },
121
+ { T_SEQ, 0, 0, seq4 },
122
+ end_node
123
+ };
124
+ struct test_node stream[] = {
125
+ { T_MAP, 0, 0, map },
126
+ end_node
127
+ };
128
+
129
+ ---
130
+ test: Sequence of sequences
131
+ spec: 2.5
132
+ yaml: |
133
+ - [ name , hr , avg ]
134
+ - [ Mark McGwire , 65 , 0.278 ]
135
+ - [ Sammy Sosa , 63 , 0.288 ]
136
+ php: |
137
+ array(
138
+ array( 'name', 'hr', 'avg' ),
139
+ array( 'Mark McGwire', 65, 0.278 ),
140
+ array( 'Sammy Sosa', 63, 0.288 )
141
+ )
142
+ ---
143
+ test: Mapping of mappings
144
+ todo: true
145
+ spec: 2.6
146
+ yaml: |
147
+ Mark McGwire: {hr: 65, avg: 0.278}
148
+ Sammy Sosa: {
149
+ hr: 63,
150
+ avg: 0.288
151
+ }
152
+ php: |
153
+ array(
154
+ 'Mark McGwire' =>
155
+ array( 'hr' => 65, 'avg' => 0.278 ),
156
+ 'Sammy Sosa' =>
157
+ array( 'hr' => 63, 'avg' => 0.288 )
158
+ )
159
+ ---
160
+ test: Two documents in a stream each with a leading comment
161
+ todo: true
162
+ spec: 2.7
163
+ yaml: |
164
+ # Ranking of 1998 home runs
165
+ ---
166
+ - Mark McGwire
167
+ - Sammy Sosa
168
+ - Ken Griffey
169
+
170
+ # Team ranking
171
+ ---
172
+ - Chicago Cubs
173
+ - St Louis Cardinals
174
+ ruby: |
175
+ y = YAML::Stream.new
176
+ y.add( [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ] )
177
+ y.add( [ 'Chicago Cubs', 'St Louis Cardinals' ] )
178
+ documents: 2
179
+
180
+ ---
181
+ test: Play by play feed from a game
182
+ todo: true
183
+ spec: 2.8
184
+ yaml: |
185
+ ---
186
+ time: 20:03:20
187
+ player: Sammy Sosa
188
+ action: strike (miss)
189
+ ...
190
+ ---
191
+ time: 20:03:47
192
+ player: Sammy Sosa
193
+ action: grand slam
194
+ ...
195
+ perl: |
196
+ [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ]
197
+ documents: 2
198
+
199
+ ---
200
+ test: Single document with two comments
201
+ spec: 2.9
202
+ yaml: |
203
+ hr: # 1998 hr ranking
204
+ - Mark McGwire
205
+ - Sammy Sosa
206
+ rbi:
207
+ # 1998 rbi ranking
208
+ - Sammy Sosa
209
+ - Ken Griffey
210
+ php: |
211
+ array(
212
+ 'hr' => array( 'Mark McGwire', 'Sammy Sosa' ),
213
+ 'rbi' => array( 'Sammy Sosa', 'Ken Griffey' )
214
+ )
215
+ ---
216
+ test: Node for Sammy Sosa appears twice in this document
217
+ spec: 2.10
218
+ yaml: |
219
+ ---
220
+ hr:
221
+ - Mark McGwire
222
+ # Following node labeled SS
223
+ - &SS Sammy Sosa
224
+ rbi:
225
+ - *SS # Subsequent occurrence
226
+ - Ken Griffey
227
+ php: |
228
+ array(
229
+ 'hr' =>
230
+ array('Mark McGwire', 'Sammy Sosa'),
231
+ 'rbi' =>
232
+ array('Sammy Sosa', 'Ken Griffey')
233
+ )
234
+ ---
235
+ test: Mapping between sequences
236
+ todo: true
237
+ spec: 2.11
238
+ yaml: |
239
+ ? # PLAY SCHEDULE
240
+ - Detroit Tigers
241
+ - Chicago Cubs
242
+ :
243
+ - 2001-07-23
244
+
245
+ ? [ New York Yankees,
246
+ Atlanta Braves ]
247
+ : [ 2001-07-02, 2001-08-12,
248
+ 2001-08-14 ]
249
+ ruby: |
250
+ {
251
+ [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ],
252
+ [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ]
253
+ }
254
+ syck: |
255
+ struct test_node seq1[] = {
256
+ { T_STR, 0, "New York Yankees" },
257
+ { T_STR, 0, "Atlanta Braves" },
258
+ end_node
259
+ };
260
+ struct test_node seq2[] = {
261
+ { T_STR, 0, "2001-07-02" },
262
+ { T_STR, 0, "2001-08-12" },
263
+ { T_STR, 0, "2001-08-14" },
264
+ end_node
265
+ };
266
+ struct test_node seq3[] = {
267
+ { T_STR, 0, "Detroit Tigers" },
268
+ { T_STR, 0, "Chicago Cubs" },
269
+ end_node
270
+ };
271
+ struct test_node seq4[] = {
272
+ { T_STR, 0, "2001-07-23" },
273
+ end_node
274
+ };
275
+ struct test_node map[] = {
276
+ { T_SEQ, 0, 0, seq3 },
277
+ { T_SEQ, 0, 0, seq4 },
278
+ { T_SEQ, 0, 0, seq1 },
279
+ { T_SEQ, 0, 0, seq2 },
280
+ end_node
281
+ };
282
+ struct test_node stream[] = {
283
+ { T_MAP, 0, 0, map },
284
+ end_node
285
+ };
286
+
287
+ ---
288
+ test: Sequence key shortcut
289
+ spec: 2.12
290
+ yaml: |
291
+ ---
292
+ # products purchased
293
+ - item : Super Hoop
294
+ quantity: 1
295
+ - item : Basketball
296
+ quantity: 4
297
+ - item : Big Shoes
298
+ quantity: 1
299
+ php: |
300
+ array (
301
+ array (
302
+ 'item' => 'Super Hoop',
303
+ 'quantity' => 1,
304
+ ),
305
+ array (
306
+ 'item' => 'Basketball',
307
+ 'quantity' => 4,
308
+ ),
309
+ array (
310
+ 'item' => 'Big Shoes',
311
+ 'quantity' => 1,
312
+ )
313
+ )
314
+ perl: |
315
+ [
316
+ { item => 'Super Hoop', quantity => 1 },
317
+ { item => 'Basketball', quantity => 4 },
318
+ { item => 'Big Shoes', quantity => 1 }
319
+ ]
320
+
321
+ ruby: |
322
+ [
323
+ { 'item' => 'Super Hoop', 'quantity' => 1 },
324
+ { 'item' => 'Basketball', 'quantity' => 4 },
325
+ { 'item' => 'Big Shoes', 'quantity' => 1 }
326
+ ]
327
+ python: |
328
+ [
329
+ { 'item': 'Super Hoop', 'quantity': 1 },
330
+ { 'item': 'Basketball', 'quantity': 4 },
331
+ { 'item': 'Big Shoes', 'quantity': 1 }
332
+ ]
333
+ syck: |
334
+ struct test_node map1[] = {
335
+ { T_STR, 0, "item" },
336
+ { T_STR, 0, "Super Hoop" },
337
+ { T_STR, 0, "quantity" },
338
+ { T_STR, 0, "1" },
339
+ end_node
340
+ };
341
+ struct test_node map2[] = {
342
+ { T_STR, 0, "item" },
343
+ { T_STR, 0, "Basketball" },
344
+ { T_STR, 0, "quantity" },
345
+ { T_STR, 0, "4" },
346
+ end_node
347
+ };
348
+ struct test_node map3[] = {
349
+ { T_STR, 0, "item" },
350
+ { T_STR, 0, "Big Shoes" },
351
+ { T_STR, 0, "quantity" },
352
+ { T_STR, 0, "1" },
353
+ end_node
354
+ };
355
+ struct test_node seq[] = {
356
+ { T_MAP, 0, 0, map1 },
357
+ { T_MAP, 0, 0, map2 },
358
+ { T_MAP, 0, 0, map3 },
359
+ end_node
360
+ };
361
+ struct test_node stream[] = {
362
+ { T_SEQ, 0, 0, seq },
363
+ end_node
364
+ };
365
+
366
+
367
+ ---
368
+ test: Literal perserves newlines
369
+ todo: true
370
+ spec: 2.13
371
+ yaml: |
372
+ # ASCII Art
373
+ --- |
374
+ \//||\/||
375
+ // || ||_
376
+ perl: |
377
+ "\\//||\\/||\n// || ||_\n"
378
+ ruby: |
379
+ "\\//||\\/||\n// || ||_\n"
380
+ python: |
381
+ [
382
+ flushLeft(
383
+ """
384
+ \//||\/||
385
+ // || ||_
386
+ """
387
+ )
388
+ ]
389
+ syck: |
390
+ struct test_node stream[] = {
391
+ { T_STR, 0, "\\//||\\/||\n// || ||_\n" },
392
+ end_node
393
+ };
394
+
395
+ ---
396
+ test: Folded treats newlines as a space
397
+ todo: true
398
+ spec: 2.14
399
+ yaml: |
400
+ ---
401
+ Mark McGwire's
402
+ year was crippled
403
+ by a knee injury.
404
+ perl: |
405
+ "Mark McGwire's year was crippled by a knee injury."
406
+ ruby: |
407
+ "Mark McGwire's year was crippled by a knee injury."
408
+ python: |
409
+ [ "Mark McGwire's year was crippled by a knee injury." ]
410
+ syck: |
411
+ struct test_node stream[] = {
412
+ { T_STR, 0, "Mark McGwire's year was crippled by a knee injury." },
413
+ end_node
414
+ };
415
+
416
+ ---
417
+ test: Newlines preserved for indented and blank lines
418
+ todo: true
419
+ spec: 2.15
420
+ yaml: |
421
+ --- >
422
+ Sammy Sosa completed another
423
+ fine season with great stats.
424
+
425
+ 63 Home Runs
426
+ 0.288 Batting Average
427
+
428
+ What a year!
429
+ perl: |
430
+ "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n"
431
+ ruby: |
432
+ "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n"
433
+ python: |
434
+ [
435
+ flushLeft(
436
+ """
437
+ Sammy Sosa completed another fine season with great stats.
438
+
439
+ 63 Home Runs
440
+ 0.288 Batting Average
441
+
442
+ What a year!
443
+ """
444
+ )
445
+ ]
446
+ syck: |
447
+ struct test_node stream[] = {
448
+ { T_STR, 0, "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n" },
449
+ end_node
450
+ };
451
+
452
+
453
+ ---
454
+ test: Indentation determines scope
455
+ spec: 2.16
456
+ yaml: |
457
+ name: Mark McGwire
458
+ accomplishment: >
459
+ Mark set a major league
460
+ home run record in 1998.
461
+ stats: |
462
+ 65 Home Runs
463
+ 0.278 Batting Average
464
+ php: |
465
+ array(
466
+ 'name' => 'Mark McGwire',
467
+ 'accomplishment' => "Mark set a major league home run record in 1998.\n",
468
+ 'stats' => "65 Home Runs\n0.278 Batting Average\n"
469
+ )
470
+ ---
471
+ test: Quoted scalars
472
+ todo: true
473
+ spec: 2.17
474
+ yaml: |
475
+ unicode: "Sosa did fine.\u263A"
476
+ control: "\b1998\t1999\t2000\n"
477
+ hexesc: "\x0D\x0A is \r\n"
478
+
479
+ single: '"Howdy!" he cried.'
480
+ quoted: ' # not a ''comment''.'
481
+ tie-fighter: '|\-*-/|'
482
+ ruby: |
483
+ {
484
+ "tie-fighter" => "|\\-*-/|",
485
+ "control"=>"\0101998\t1999\t2000\n",
486
+ "unicode"=>"Sosa did fine." + ["263A".hex ].pack('U*'),
487
+ "quoted"=>" # not a 'comment'.",
488
+ "single"=>"\"Howdy!\" he cried.",
489
+ "hexesc"=>"\r\n is \r\n"
490
+ }
491
+ ---
492
+ test: Multiline flow scalars
493
+ todo: true
494
+ spec: 2.18
495
+ yaml: |
496
+ plain:
497
+ This unquoted scalar
498
+ spans many lines.
499
+
500
+ quoted: "So does this
501
+ quoted scalar.\n"
502
+ ruby: |
503
+ {
504
+ 'plain' => 'This unquoted scalar spans many lines.',
505
+ 'quoted' => "So does this quoted scalar.\n"
506
+ }
507
+ ---
508
+ test: Integers
509
+ spec: 2.19
510
+ yaml: |
511
+ canonical: 12345
512
+ decimal: +12,345
513
+ octal: 014
514
+ hexadecimal: 0xC
515
+ php: |
516
+ array(
517
+ 'canonical' => 12345,
518
+ 'decimal' => 12345,
519
+ 'octal' => 014,
520
+ 'hexadecimal' => 0xC
521
+ )
522
+ ---
523
+ # FIX: spec shows parens around -inf and NaN
524
+ test: Floating point
525
+ spec: 2.20
526
+ yaml: |
527
+ canonical: 1.23015e+3
528
+ exponential: 12.3015e+02
529
+ fixed: 1,230.15
530
+ negative infinity: -.inf
531
+ not a number: .NaN
532
+ php: |
533
+ array(
534
+ 'canonical' => 1230.15,
535
+ 'exponential' => 1230.15,
536
+ 'fixed' => 1230.15,
537
+ 'negative infinity' => log(0),
538
+ 'not a number' => -log(0),
539
+ )
540
+ ---
541
+ test: Miscellaneous
542
+ spec: 2.21
543
+ yaml: |
544
+ null: ~
545
+ true: true
546
+ false: false
547
+ string: '12345'
548
+ php: |
549
+ array(
550
+ '' => null,
551
+ 1 => true,
552
+ 0 => false,
553
+ 'string' => '12345'
554
+ )
555
+ ---
556
+ test: Timestamps
557
+ todo: true
558
+ spec: 2.22
559
+ yaml: |
560
+ canonical: 2001-12-15T02:59:43.1Z
561
+ iso8601: 2001-12-14t21:59:43.10-05:00
562
+ spaced: 2001-12-14 21:59:43.10 -05:00
563
+ date: 2002-12-14 # Time is noon UTC
564
+ php: |
565
+ array(
566
+ 'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, 0.10 ),
567
+ 'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ),
568
+ 'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ),
569
+ 'date' => Date.new( 2002, 12, 14 )
570
+ )
571
+ ---
572
+ test: legacy Timestamps test
573
+ todo: true
574
+ spec: legacy D4
575
+ yaml: |
576
+ canonical: 2001-12-15T02:59:43.00Z
577
+ iso8601: 2001-02-28t21:59:43.00-05:00
578
+ spaced: 2001-12-14 21:59:43.00 -05:00
579
+ date: 2002-12-14
580
+ php: |
581
+ array(
582
+ 'canonical' => Time::utc( 2001, 12, 15, 2, 59, 43, 0 ),
583
+ 'iso8601' => YAML::mktime( 2001, 2, 28, 21, 59, 43, 0, "-05:00" ),
584
+ 'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0, "-05:00" ),
585
+ 'date' => Date.new( 2002, 12, 14 )
586
+ )
587
+ ---
588
+ test: Various explicit families
589
+ todo: true
590
+ spec: 2.23
591
+ yaml: |
592
+ not-date: !str 2002-04-28
593
+ picture: !binary |
594
+ R0lGODlhDAAMAIQAAP//9/X
595
+ 17unp5WZmZgAAAOfn515eXv
596
+ Pz7Y6OjuDg4J+fn5OTk6enp
597
+ 56enmleECcgggoBADs=
598
+
599
+ application specific tag: !!something |
600
+ The semantics of the tag
601
+ above may be different for
602
+ different documents.
603
+
604
+ ruby-setup: |
605
+ YAML.add_private_type( "something" ) do |type, val|
606
+ "SOMETHING: #{val}"
607
+ end
608
+ ruby: |
609
+ {
610
+ 'not-date' => '2002-04-28',
611
+ 'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;",
612
+ 'application specific tag' => "SOMETHING: The semantics of the tag\nabove may be different for\ndifferent documents.\n"
613
+ }
614
+ ---
615
+ test: Application specific family
616
+ todo: true
617
+ spec: 2.24
618
+ yaml: |
619
+ # Establish a tag prefix
620
+ --- !clarkevans.com,2002/graph/^shape
621
+ # Use the prefix: shorthand for
622
+ # !clarkevans.com,2002/graph/circle
623
+ - !^circle
624
+ center: &ORIGIN {x: 73, 'y': 129}
625
+ radius: 7
626
+ - !^line # !clarkevans.com,2002/graph/line
627
+ start: *ORIGIN
628
+ finish: { x: 89, 'y': 102 }
629
+ - !^label
630
+ start: *ORIGIN
631
+ color: 0xFFEEBB
632
+ value: Pretty vector drawing.
633
+ ruby-setup: |
634
+ YAML.add_domain_type( "clarkevans.com,2002", 'graph/shape' ) { |type, val|
635
+ if Array === val
636
+ val << "Shape Container"
637
+ val
638
+ else
639
+ raise YAML::Error, "Invalid graph of class #{ val.class }: " + val.inspect
640
+ end
641
+ }
642
+ one_shape_proc = Proc.new { |type, val|
643
+ scheme, domain, type = type.split( /:/, 3 )
644
+ if val.is_a? ::Hash
645
+ val['TYPE'] = "Shape: #{type}"
646
+ val
647
+ else
648
+ raise YAML::Error, "Invalid graph of class #{ val.class }: " + val.inspect
649
+ end
650
+ }
651
+ YAML.add_domain_type( "clarkevans.com,2002", 'graph/circle', &one_shape_proc )
652
+ YAML.add_domain_type( "clarkevans.com,2002", 'graph/line', &one_shape_proc )
653
+ YAML.add_domain_type( "clarkevans.com,2002", 'graph/label', &one_shape_proc )
654
+ ruby: |
655
+ [
656
+ {
657
+ "radius" => 7,
658
+ "center"=>
659
+ {
660
+ "x" => 73,
661
+ "y" => 129
662
+ },
663
+ "TYPE" => "Shape: graph/circle"
664
+ }, {
665
+ "finish" =>
666
+ {
667
+ "x" => 89,
668
+ "y" => 102
669
+ },
670
+ "TYPE" => "Shape: graph/line",
671
+ "start" =>
672
+ {
673
+ "x" => 73,
674
+ "y" => 129
675
+ }
676
+ }, {
677
+ "TYPE" => "Shape: graph/label",
678
+ "value" => "Pretty vector drawing.",
679
+ "start" =>
680
+ {
681
+ "x" => 73,
682
+ "y" => 129
683
+ },
684
+ "color" => 16772795
685
+ },
686
+ "Shape Container"
687
+ ]
688
+ # ---
689
+ # test: Unordered set
690
+ # spec: 2.25
691
+ # yaml: |
692
+ # # sets are represented as a
693
+ # # mapping where each key is
694
+ # # associated with the empty string
695
+ # --- !set
696
+ # ? Mark McGwire
697
+ # ? Sammy Sosa
698
+ # ? Ken Griff
699
+ ---
700
+ test: Ordered mappings
701
+ todo: true
702
+ spec: 2.26
703
+ yaml: |
704
+ # ordered maps are represented as
705
+ # a sequence of mappings, with
706
+ # each mapping having one key
707
+ --- !omap
708
+ - Mark McGwire: 65
709
+ - Sammy Sosa: 63
710
+ - Ken Griffy: 58
711
+ ruby: |
712
+ YAML::Omap[
713
+ 'Mark McGwire', 65,
714
+ 'Sammy Sosa', 63,
715
+ 'Ken Griffy', 58
716
+ ]
717
+ ---
718
+ test: Invoice
719
+ dump_skip: true
720
+ spec: 2.27
721
+ yaml: |
722
+ --- !clarkevans.com,2002/^invoice
723
+ invoice: 34843
724
+ date : 2001-01-23
725
+ bill-to: &id001
726
+ given : Chris
727
+ family : Dumars
728
+ address:
729
+ lines: |
730
+ 458 Walkman Dr.
731
+ Suite #292
732
+ city : Royal Oak
733
+ state : MI
734
+ postal : 48046
735
+ ship-to: *id001
736
+ product:
737
+ -
738
+ sku : BL394D
739
+ quantity : 4
740
+ description : Basketball
741
+ price : 450.00
742
+ -
743
+ sku : BL4438H
744
+ quantity : 1
745
+ description : Super Hoop
746
+ price : 2392.00
747
+ tax : 251.42
748
+ total: 4443.52
749
+ comments: >
750
+ Late afternoon is best.
751
+ Backup contact is Nancy
752
+ Billsmer @ 338-4338.
753
+ php: |
754
+ array(
755
+ 'invoice' => 34843, 'date' => mktime(0, 0, 0, 1, 23, 2001),
756
+ 'bill-to' =>
757
+ array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) )
758
+ , 'ship-to' =>
759
+ array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) )
760
+ , 'product' =>
761
+ array(
762
+ array( 'sku' => 'BL394D', 'quantity' => 4, 'description' => 'Basketball', 'price' => 450.00 ),
763
+ array( 'sku' => 'BL4438H', 'quantity' => 1, 'description' => 'Super Hoop', 'price' => 2392.00 )
764
+ ),
765
+ 'tax' => 251.42, 'total' => 4443.52,
766
+ 'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n"
767
+ )
768
+ ---
769
+ test: Log file
770
+ todo: true
771
+ spec: 2.28
772
+ yaml: |
773
+ ---
774
+ Time: 2001-11-23 15:01:42 -05:00
775
+ User: ed
776
+ Warning: >
777
+ This is an error message
778
+ for the log file
779
+ ---
780
+ Time: 2001-11-23 15:02:31 -05:00
781
+ User: ed
782
+ Warning: >
783
+ A slightly different error
784
+ message.
785
+ ---
786
+ Date: 2001-11-23 15:03:17 -05:00
787
+ User: ed
788
+ Fatal: >
789
+ Unknown variable "bar"
790
+ Stack:
791
+ - file: TopClass.py
792
+ line: 23
793
+ code: |
794
+ x = MoreObject("345\n")
795
+ - file: MoreClass.py
796
+ line: 58
797
+ code: |-
798
+ foo = bar
799
+ ruby: |
800
+ y = YAML::Stream.new
801
+ y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ),
802
+ 'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } )
803
+ y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ),
804
+ 'User' => 'ed', 'Warning' => "A slightly different error message.\n" } )
805
+ y.add( { 'Date' => YAML::mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ),
806
+ 'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n",
807
+ 'Stack' => [
808
+ { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" },
809
+ { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } )
810
+ documents: 3
811
+
812
+ ---
813
+ test: Throwaway comments
814
+ yaml: |
815
+ ### These are four throwaway comment ###
816
+
817
+ ### lines (the second line is empty). ###
818
+ this: | # Comments may trail lines.
819
+ contains three lines of text.
820
+ The third one starts with a
821
+ # character. This isn't a comment.
822
+
823
+ # These are three throwaway comment
824
+ # lines (the first line is empty).
825
+ php: |
826
+ array(
827
+ 'this' => "contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"
828
+ )
829
+ ---
830
+ test: Document with a single value
831
+ todo: true
832
+ yaml: |
833
+ --- >
834
+ This YAML stream contains a single text value.
835
+ The next stream is a log file - a sequence of
836
+ log entries. Adding an entry to the log is a
837
+ simple matter of appending it at the end.
838
+ ruby: |
839
+ "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n"
840
+ ---
841
+ test: Document stream
842
+ todo: true
843
+ yaml: |
844
+ ---
845
+ at: 2001-08-12 09:25:00.00 Z
846
+ type: GET
847
+ HTTP: '1.0'
848
+ url: '/index.html'
849
+ ---
850
+ at: 2001-08-12 09:25:10.00 Z
851
+ type: GET
852
+ HTTP: '1.0'
853
+ url: '/toc.html'
854
+ ruby: |
855
+ y = YAML::Stream.new
856
+ y.add( {
857
+ 'at' => Time::utc( 2001, 8, 12, 9, 25, 00 ),
858
+ 'type' => 'GET',
859
+ 'HTTP' => '1.0',
860
+ 'url' => '/index.html'
861
+ } )
862
+ y.add( {
863
+ 'at' => Time::utc( 2001, 8, 12, 9, 25, 10 ),
864
+ 'type' => 'GET',
865
+ 'HTTP' => '1.0',
866
+ 'url' => '/toc.html'
867
+ } )
868
+ documents: 2
869
+
870
+ ---
871
+ test: Top level mapping
872
+ yaml: |
873
+ # This stream is an example of a top-level mapping.
874
+ invoice : 34843
875
+ date : 2001-01-23
876
+ total : 4443.52
877
+ php: |
878
+ array(
879
+ 'invoice' => 34843,
880
+ 'date' => mktime(0, 0, 0, 1, 23, 2001),
881
+ 'total' => 4443.52
882
+ )
883
+ ---
884
+ test: Single-line documents
885
+ todo: true
886
+ yaml: |
887
+ # The following is a sequence of three documents.
888
+ # The first contains an empty mapping, the second
889
+ # an empty sequence, and the last an empty string.
890
+ --- {}
891
+ --- [ ]
892
+ --- ''
893
+ ruby: |
894
+ y = YAML::Stream.new
895
+ y.add( {} )
896
+ y.add( [] )
897
+ y.add( '' )
898
+ documents: 3
899
+
900
+ ---
901
+ test: Document with pause
902
+ todo: true
903
+ yaml: |
904
+ # A communication channel based on a YAML stream.
905
+ ---
906
+ sent at: 2002-06-06 11:46:25.10 Z
907
+ payload: Whatever
908
+ # Receiver can process this as soon as the following is sent:
909
+ ...
910
+ # Even if the next message is sent long after:
911
+ ---
912
+ sent at: 2002-06-06 12:05:53.47 Z
913
+ payload: Whatever
914
+ ...
915
+ ruby: |
916
+ y = YAML::Stream.new
917
+ y.add(
918
+ { 'sent at' => YAML::mktime( 2002, 6, 6, 11, 46, 25, 0.10 ),
919
+ 'payload' => 'Whatever' }
920
+ )
921
+ y.add(
922
+ { "payload" => "Whatever", "sent at" => YAML::mktime( 2002, 6, 6, 12, 5, 53, 0.47 ) }
923
+ )
924
+ documents: 2
925
+
926
+ ---
927
+ test: Explicit typing
928
+ yaml: |
929
+ integer: 12
930
+ also int: ! "12"
931
+ string: !str 12
932
+ php: |
933
+ array( 'integer' => 12, 'also int' => 12, 'string' => '12' )
934
+ ---
935
+ test: Private types
936
+ todo: true
937
+ yaml: |
938
+ # Both examples below make use of the 'x-private:ball'
939
+ # type family URI, but with different semantics.
940
+ ---
941
+ pool: !!ball
942
+ number: 8
943
+ color: black
944
+ ---
945
+ bearing: !!ball
946
+ material: steel
947
+ ruby: |
948
+ y = YAML::Stream.new
949
+ y.add( { 'pool' =>
950
+ YAML::PrivateType.new( 'ball',
951
+ { 'number' => 8, 'color' => 'black' } ) }
952
+ )
953
+ y.add( { 'bearing' =>
954
+ YAML::PrivateType.new( 'ball',
955
+ { 'material' => 'steel' } ) }
956
+ )
957
+ documents: 2
958
+
959
+ ---
960
+ test: Type family under yaml.org
961
+ yaml: |
962
+ # The URI is 'tag:yaml.org,2002:str'
963
+ - !str a Unicode string
964
+ php: |
965
+ array( 'a Unicode string' )
966
+ ---
967
+ test: Type family under perl.yaml.org
968
+ todo: true
969
+ yaml: |
970
+ # The URI is 'tag:perl.yaml.org,2002:Text::Tabs'
971
+ - !perl/Text::Tabs {}
972
+ ruby: |
973
+ [ YAML::DomainType.new( 'perl.yaml.org,2002', 'Text::Tabs', {} ) ]
974
+ ---
975
+ test: Type family under clarkevans.com
976
+ todo: true
977
+ yaml: |
978
+ # The URI is 'tag:clarkevans.com,2003-02:timesheet'
979
+ - !clarkevans.com,2003-02/timesheet {}
980
+ ruby: |
981
+ [ YAML::DomainType.new( 'clarkevans.com,2003-02', 'timesheet', {} ) ]
982
+ ---
983
+ test: URI Escaping
984
+ todo: true
985
+ yaml: |
986
+ same:
987
+ - !domain.tld,2002/type\x30 value
988
+ - !domain.tld,2002/type0 value
989
+ different: # As far as the YAML parser is concerned
990
+ - !domain.tld,2002/type%30 value
991
+ - !domain.tld,2002/type0 value
992
+ ruby-setup: |
993
+ YAML.add_domain_type( "domain.tld,2002", "type0" ) { |type, val|
994
+ "ONE: #{val}"
995
+ }
996
+ YAML.add_domain_type( "domain.tld,2002", "type%30" ) { |type, val|
997
+ "TWO: #{val}"
998
+ }
999
+ ruby: |
1000
+ { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value', 'ONE: value' ] }
1001
+ ---
1002
+ test: URI Prefixing
1003
+ todo: true
1004
+ yaml: |
1005
+ # 'tag:domain.tld,2002:invoice' is some type family.
1006
+ invoice: !domain.tld,2002/^invoice
1007
+ # 'seq' is shorthand for 'tag:yaml.org,2002:seq'.
1008
+ # This does not effect '^customer' below
1009
+ # because it is does not specify a prefix.
1010
+ customers: !seq
1011
+ # '^customer' is shorthand for the full
1012
+ # notation 'tag:domain.tld,2002:customer'.
1013
+ - !^customer
1014
+ given : Chris
1015
+ family : Dumars
1016
+ ruby-setup: |
1017
+ YAML.add_domain_type( "domain.tld,2002", /(invoice|customer)/ ) { |type, val|
1018
+ if val.is_a? ::Hash
1019
+ scheme, domain, type = type.split( /:/, 3 )
1020
+ val['type'] = "domain #{type}"
1021
+ val
1022
+ else
1023
+ raise YAML::Error, "Not a Hash in domain.tld/invoice: " + val.inspect
1024
+ end
1025
+ }
1026
+ ruby: |
1027
+ { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }
1028
+
1029
+ ---
1030
+ test: Overriding anchors
1031
+ yaml: |
1032
+ anchor : &A001 This scalar has an anchor.
1033
+ override : &A001 >
1034
+ The alias node below is a
1035
+ repeated use of this value.
1036
+ alias : *A001
1037
+ php: |
1038
+ array( 'anchor' => 'This scalar has an anchor.',
1039
+ 'override' => "The alias node below is a repeated use of this value.\n",
1040
+ 'alias' => "The alias node below is a repeated use of this value.\n" )
1041
+ ---
1042
+ test: Flow and block formatting
1043
+ todo: true
1044
+ yaml: |
1045
+ empty: []
1046
+ flow: [ one, two, three # May span lines,
1047
+ , four, # indentation is
1048
+ five ] # mostly ignored.
1049
+ block:
1050
+ - First item in top sequence
1051
+ -
1052
+ - Subordinate sequence entry
1053
+ - >
1054
+ A folded sequence entry
1055
+ - Sixth item in top sequence
1056
+ ruby: |
1057
+ { 'empty' => [], 'flow' => [ 'one', 'two', 'three', 'four', 'five' ],
1058
+ 'block' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ],
1059
+ "A folded sequence entry\n", 'Sixth item in top sequence' ] }
1060
+ ---
1061
+ test: Complete mapping test
1062
+ todo: true
1063
+ yaml: |
1064
+ empty: {}
1065
+ flow: { one: 1, two: 2 }
1066
+ spanning: { one: 1,
1067
+ two: 2 }
1068
+ block:
1069
+ first : First entry
1070
+ second:
1071
+ key: Subordinate mapping
1072
+ third:
1073
+ - Subordinate sequence
1074
+ - { }
1075
+ - Previous mapping is empty.
1076
+ - A key: value pair in a sequence.
1077
+ A second: key:value pair.
1078
+ - The previous entry is equal to the following one.
1079
+ -
1080
+ A key: value pair in a sequence.
1081
+ A second: key:value pair.
1082
+ !float 12 : This key is a float.
1083
+ ? >
1084
+ ?
1085
+ : This key had to be protected.
1086
+ "\a" : This key had to be escaped.
1087
+ ? >
1088
+ This is a
1089
+ multi-line
1090
+ folded key
1091
+ : Whose value is
1092
+ also multi-line.
1093
+ ? this also works as a key
1094
+ : with a value at the next line.
1095
+ ?
1096
+ - This key
1097
+ - is a sequence
1098
+ :
1099
+ - With a sequence value.
1100
+ ?
1101
+ This: key
1102
+ is a: mapping
1103
+ :
1104
+ with a: mapping value.
1105
+ ruby: |
1106
+ { 'empty' => {}, 'flow' => { 'one' => 1, 'two' => 2 },
1107
+ 'spanning' => { 'one' => 1, 'two' => 2 },
1108
+ 'block' => { 'first' => 'First entry', 'second' =>
1109
+ { 'key' => 'Subordinate mapping' }, 'third' =>
1110
+ [ 'Subordinate sequence', {}, 'Previous mapping is empty.',
1111
+ { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' },
1112
+ 'The previous entry is equal to the following one.',
1113
+ { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ],
1114
+ 12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.',
1115
+ "\a" => 'This key had to be escaped.',
1116
+ "This is a multi-line folded key\n" => "Whose value is also multi-line.",
1117
+ 'this also works as a key' => 'with a value at the next line.',
1118
+ [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }
1119
+ # Couldn't recreate map exactly, so we'll do a detailed check to be sure it's entact
1120
+ obj_y['block'].keys.each { |k|
1121
+ if Hash === k
1122
+ v = obj_y['block'][k]
1123
+ if k['This'] == 'key' and k['is a'] == 'mapping' and v['with a'] == 'mapping value.'
1124
+ obj_r['block'][k] = v
1125
+ end
1126
+ end
1127
+ }
1128
+ ---
1129
+ test: Literal explicit indentation
1130
+ yaml: |
1131
+ # Explicit indentation must
1132
+ # be given in all the three
1133
+ # following cases.
1134
+ leading spaces: |2
1135
+ This value starts with four spaces.
1136
+
1137
+ leading line break: |2
1138
+
1139
+ This value starts with a line break.
1140
+
1141
+ leading comment indicator: |2
1142
+ # first line starts with a
1143
+ # character.
1144
+
1145
+ # Explicit indentation may
1146
+ # also be given when it is
1147
+ # not required.
1148
+ redundant: |2
1149
+ This value is indented 2 spaces.
1150
+ php: |
1151
+ array(
1152
+ 'leading spaces' => " This value starts with four spaces.\n",
1153
+ 'leading line break' => "\nThis value starts with a line break.\n",
1154
+ 'leading comment indicator' => "# first line starts with a\n# character.\n",
1155
+ 'redundant' => "This value is indented 2 spaces.\n"
1156
+ )
1157
+ ---
1158
+ test: Chomping and keep modifiers
1159
+ yaml: |
1160
+ clipped: |
1161
+ This has one newline.
1162
+
1163
+ same as "clipped" above: "This has one newline.\n"
1164
+
1165
+ stripped: |-
1166
+ This has no newline.
1167
+
1168
+ same as "stripped" above: "This has no newline."
1169
+
1170
+ kept: |+
1171
+ This has two newlines.
1172
+
1173
+ same as "kept" above: "This has two newlines.\n\n"
1174
+ php: |
1175
+ array(
1176
+ 'clipped' => "This has one newline.\n",
1177
+ 'same as "clipped" above' => "This has one newline.\n",
1178
+ 'stripped' => 'This has no newline.',
1179
+ 'same as "stripped" above' => 'This has no newline.',
1180
+ 'kept' => "This has two newlines.\n\n",
1181
+ 'same as "kept" above' => "This has two newlines.\n\n"
1182
+ )
1183
+ ---
1184
+ test: Literal combinations
1185
+ todo: true
1186
+ yaml: |
1187
+ empty: |
1188
+
1189
+ literal: |
1190
+ The \ ' " characters may be
1191
+ freely used. Leading white
1192
+ space is significant.
1193
+
1194
+ Line breaks are significant.
1195
+ Thus this value contains one
1196
+ empty line and ends with a
1197
+ single line break, but does
1198
+ not start with one.
1199
+
1200
+ is equal to: "The \\ ' \" characters may \
1201
+ be\nfreely used. Leading white\n space \
1202
+ is significant.\n\nLine breaks are \
1203
+ significant.\nThus this value contains \
1204
+ one\nempty line and ends with a\nsingle \
1205
+ line break, but does\nnot start with one.\n"
1206
+
1207
+ # Comments may follow a block
1208
+ # scalar value. They must be
1209
+ # less indented.
1210
+
1211
+ # Modifiers may be combined in any order.
1212
+ indented and chomped: |2-
1213
+ This has no newline.
1214
+
1215
+ also written as: |-2
1216
+ This has no newline.
1217
+
1218
+ both are equal to: " This has no newline."
1219
+ php: |
1220
+ array(
1221
+ 'empty' => '',
1222
+ 'literal' => "The \\ ' \" characters may be\nfreely used. Leading white\n space " +
1223
+ "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
1224
+ "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
1225
+ 'is equal to' => "The \\ ' \" characters may be\nfreely used. Leading white\n space " +
1226
+ "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" +
1227
+ "empty line and ends with a\nsingle line break, but does\nnot start with one.\n",
1228
+ 'indented and chomped' => ' This has no newline.',
1229
+ 'also written as' => ' This has no newline.',
1230
+ 'both are equal to' => ' This has no newline.'
1231
+ )
1232
+ ---
1233
+ test: Folded combinations
1234
+ todo: true
1235
+ yaml: |
1236
+ empty: >
1237
+
1238
+ one paragraph: >
1239
+ Line feeds are converted
1240
+ to spaces, so this value
1241
+ contains no line breaks
1242
+ except for the final one.
1243
+
1244
+ multiple paragraphs: >2
1245
+
1246
+ An empty line, either
1247
+ at the start or in
1248
+ the value:
1249
+
1250
+ Is interpreted as a
1251
+ line break. Thus this
1252
+ value contains three
1253
+ line breaks.
1254
+
1255
+ indented text: >
1256
+ This is a folded
1257
+ paragraph followed
1258
+ by a list:
1259
+ * first entry
1260
+ * second entry
1261
+ Followed by another
1262
+ folded paragraph,
1263
+ another list:
1264
+
1265
+ * first entry
1266
+
1267
+ * second entry
1268
+
1269
+ And a final folded
1270
+ paragraph.
1271
+
1272
+ above is equal to: |
1273
+ This is a folded paragraph followed by a list:
1274
+ * first entry
1275
+ * second entry
1276
+ Followed by another folded paragraph, another list:
1277
+
1278
+ * first entry
1279
+
1280
+ * second entry
1281
+
1282
+ And a final folded paragraph.
1283
+
1284
+ # Explicit comments may follow
1285
+ # but must be less indented.
1286
+ php: |
1287
+ array(
1288
+ 'empty' => '',
1289
+ 'one paragraph' => 'Line feeds are converted to spaces, so this value'.
1290
+ " contains no line breaks except for the final one.\n",
1291
+ 'multiple paragraphs' => "\nAn empty line, either at the start or in the value:\n".
1292
+ "Is interpreted as a line break. Thus this value contains three line breaks.\n",
1293
+ 'indented text' => "This is a folded paragraph followed by a list:\n".
1294
+ " * first entry\n * second entry\nFollowed by another folded paragraph, ".
1295
+ "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n",
1296
+ 'above is equal to' => "This is a folded paragraph followed by a list:\n".
1297
+ " * first entry\n * second entry\nFollowed by another folded paragraph, ".
1298
+ "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n"
1299
+ )
1300
+ ---
1301
+ test: Single quotes
1302
+ todo: true
1303
+ yaml: |
1304
+ empty: ''
1305
+ second: '! : \ etc. can be used freely.'
1306
+ third: 'a single quote '' must be escaped.'
1307
+ span: 'this contains
1308
+ six spaces
1309
+
1310
+ and one
1311
+ line break'
1312
+ is same as: "this contains six spaces\nand one line break"
1313
+ php: |
1314
+ array(
1315
+ 'empty' => '',
1316
+ 'second' => '! : \\ etc. can be used freely.',
1317
+ 'third' => "a single quote ' must be escaped.",
1318
+ 'span' => "this contains six spaces\nand one line break",
1319
+ 'is same as' => "this contains six spaces\nand one line break"
1320
+ )
1321
+ ---
1322
+ test: Double quotes
1323
+ todo: true
1324
+ yaml: |
1325
+ empty: ""
1326
+ second: "! : etc. can be used freely."
1327
+ third: "a \" or a \\ must be escaped."
1328
+ fourth: "this value ends with an LF.\n"
1329
+ span: "this contains
1330
+ four \
1331
+ spaces"
1332
+ is equal to: "this contains four spaces"
1333
+ php: |
1334
+ array(
1335
+ 'empty' => '',
1336
+ 'second' => '! : etc. can be used freely.',
1337
+ 'third' => 'a " or a \\ must be escaped.',
1338
+ 'fourth' => "this value ends with an LF.\n",
1339
+ 'span' => "this contains four spaces",
1340
+ 'is equal to' => "this contains four spaces"
1341
+ )
1342
+ ---
1343
+ test: Unquoted strings
1344
+ todo: true
1345
+ yaml: |
1346
+ first: There is no unquoted empty string.
1347
+
1348
+ second: 12 ## This is an integer.
1349
+
1350
+ third: !str 12 ## This is a string.
1351
+
1352
+ span: this contains
1353
+ six spaces
1354
+
1355
+ and one
1356
+ line break
1357
+
1358
+ indicators: this has no comments.
1359
+ #:foo and bar# are
1360
+ both text.
1361
+
1362
+ flow: [ can span
1363
+ lines, # comment
1364
+ like
1365
+ this ]
1366
+
1367
+ note: { one-line keys: but multi-line values }
1368
+
1369
+ php: |
1370
+ array(
1371
+ 'first' => 'There is no unquoted empty string.',
1372
+ 'second' => 12,
1373
+ 'third' => '12',
1374
+ 'span' => "this contains six spaces\nand one line break",
1375
+ 'indicators' => "this has no comments. #:foo and bar# are both text.",
1376
+ 'flow' => [ 'can span lines', 'like this' ],
1377
+ 'note' => { 'one-line keys' => 'but multi-line values' }
1378
+ )
1379
+ ---
1380
+ test: Spanning sequences
1381
+ todo: true
1382
+ yaml: |
1383
+ # The following are equal seqs
1384
+ # with different identities.
1385
+ flow: [ one, two ]
1386
+ spanning: [ one,
1387
+ two ]
1388
+ block:
1389
+ - one
1390
+ - two
1391
+ php: |
1392
+ array(
1393
+ 'flow' => [ 'one', 'two' ],
1394
+ 'spanning' => [ 'one', 'two' ],
1395
+ 'block' => [ 'one', 'two' ]
1396
+ )
1397
+ ---
1398
+ test: Flow mappings
1399
+ yaml: |
1400
+ # The following are equal maps
1401
+ # with different identities.
1402
+ flow: { one: 1, two: 2 }
1403
+ block:
1404
+ one: 1
1405
+ two: 2
1406
+ php: |
1407
+ array(
1408
+ 'flow' => array( 'one' => 1, 'two' => 2 ),
1409
+ 'block' => array( 'one' => 1, 'two' => 2 )
1410
+ )
1411
+ ---
1412
+ test: Representations of 12
1413
+ todo: true
1414
+ yaml: |
1415
+ - 12 # An integer
1416
+ # The following scalars
1417
+ # are loaded to the
1418
+ # string value '1' '2'.
1419
+ - !str 12
1420
+ - '12'
1421
+ - "12"
1422
+ - "\
1423
+ 1\
1424
+ 2\
1425
+ "
1426
+ # Strings containing paths and regexps can be unquoted:
1427
+ - /foo/bar
1428
+ - d:/foo/bar
1429
+ - foo/bar
1430
+ - /a.*b/
1431
+ php: |
1432
+ array( 12, '12', '12', '12', '12', '/foo/bar', 'd:/foo/bar', 'foo/bar', '/a.*b/' )
1433
+ ---
1434
+ test: "Null"
1435
+ todo: true
1436
+ yaml: |
1437
+ canonical: ~
1438
+
1439
+ english: null
1440
+
1441
+ # This sequence has five
1442
+ # entries, two with values.
1443
+ sparse:
1444
+ - ~
1445
+ - 2nd entry
1446
+ - Null
1447
+ - 4th entry
1448
+ -
1449
+
1450
+ four: This mapping has five keys,
1451
+ only two with values.
1452
+
1453
+ php: |
1454
+ array (
1455
+ 'canonical' => null,
1456
+ 'english' => null,
1457
+ 'sparse' => array( null, '2nd entry', null, '4th entry', null ]),
1458
+ 'four' => 'This mapping has five keys, only two with values.'
1459
+ )
1460
+ ---
1461
+ test: Omap
1462
+ todo: true
1463
+ yaml: |
1464
+ # Explicitly typed dictionary.
1465
+ Bestiary: !omap
1466
+ - aardvark: African pig-like ant eater. Ugly.
1467
+ - anteater: South-American ant eater. Two species.
1468
+ - anaconda: South-American constrictor snake. Scary.
1469
+ # Etc.
1470
+ ruby: |
1471
+ {
1472
+ 'Bestiary' => YAML::Omap[
1473
+ 'aardvark', 'African pig-like ant eater. Ugly.',
1474
+ 'anteater', 'South-American ant eater. Two species.',
1475
+ 'anaconda', 'South-American constrictor snake. Scary.'
1476
+ ]
1477
+ }
1478
+
1479
+ ---
1480
+ test: Pairs
1481
+ todo: true
1482
+ yaml: |
1483
+ # Explicitly typed pairs.
1484
+ tasks: !pairs
1485
+ - meeting: with team.
1486
+ - meeting: with boss.
1487
+ - break: lunch.
1488
+ - meeting: with client.
1489
+ ruby: |
1490
+ {
1491
+ 'tasks' => YAML::Pairs[
1492
+ 'meeting', 'with team.',
1493
+ 'meeting', 'with boss.',
1494
+ 'break', 'lunch.',
1495
+ 'meeting', 'with client.'
1496
+ ]
1497
+ }
1498
+
1499
+ ---
1500
+ test: Set
1501
+ todo: true
1502
+ yaml: |
1503
+ # Explicitly typed set.
1504
+ baseball players: !set
1505
+ Mark McGwire:
1506
+ Sammy Sosa:
1507
+ Ken Griffey:
1508
+ ruby: |
1509
+ {
1510
+ 'baseball players' => YAML::Set[
1511
+ 'Mark McGwire', nil,
1512
+ 'Sammy Sosa', nil,
1513
+ 'Ken Griffey', nil
1514
+ ]
1515
+ }
1516
+
1517
+ ---
1518
+ test: Boolean
1519
+ yaml: |
1520
+ false: used as key
1521
+ logical: true
1522
+ answer: false
1523
+ php: |
1524
+ array(
1525
+ false => 'used as key',
1526
+ 'logical' => true,
1527
+ 'answer' => false
1528
+ )
1529
+ ---
1530
+ test: Integer
1531
+ yaml: |
1532
+ canonical: 12345
1533
+ decimal: +12,345
1534
+ octal: 014
1535
+ hexadecimal: 0xC
1536
+ php: |
1537
+ array(
1538
+ 'canonical' => 12345,
1539
+ 'decimal' => 12345,
1540
+ 'octal' => 12,
1541
+ 'hexadecimal' => 12
1542
+ )
1543
+ ---
1544
+ test: Float
1545
+ yaml: |
1546
+ canonical: 1.23015e+3
1547
+ exponential: 12.3015e+02
1548
+ fixed: 1,230.15
1549
+ negative infinity: -.inf
1550
+ not a number: .NaN
1551
+ php: |
1552
+ array(
1553
+ 'canonical' => 1230.15,
1554
+ 'exponential' => 1230.15,
1555
+ 'fixed' => 1230.15,
1556
+ 'negative infinity' => log(0),
1557
+ 'not a number' => -log(0)
1558
+ )
1559
+ ---
1560
+ test: Timestamp
1561
+ todo: true
1562
+ yaml: |
1563
+ canonical: 2001-12-15T02:59:43.1Z
1564
+ valid iso8601: 2001-12-14t21:59:43.10-05:00
1565
+ space separated: 2001-12-14 21:59:43.10 -05:00
1566
+ date (noon UTC): 2002-12-14
1567
+ ruby: |
1568
+ array(
1569
+ 'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, 0.10 ),
1570
+ 'valid iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ),
1571
+ 'space separated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ),
1572
+ 'date (noon UTC)' => Date.new( 2002, 12, 14 )
1573
+ )
1574
+ ---
1575
+ test: Binary
1576
+ todo: true
1577
+ yaml: |
1578
+ canonical: !binary "\
1579
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\
1580
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\
1581
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\
1582
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs="
1583
+ base64: !binary |
1584
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
1585
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
1586
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
1587
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=
1588
+ description: >
1589
+ The binary value above is a tiny arrow
1590
+ encoded as a gif image.
1591
+ ruby-setup: |
1592
+ arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005, \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;"
1593
+ ruby: |
1594
+ {
1595
+ 'canonical' => arrow_gif,
1596
+ 'base64' => arrow_gif,
1597
+ 'description' => "The binary value above is a tiny arrow encoded as a gif image.\n"
1598
+ }
1599
+
1600
+ ---
1601
+ test: Merge key
1602
+ todo: true
1603
+ yaml: |
1604
+ ---
1605
+ - &CENTER { x: 1, y: 2 }
1606
+ - &LEFT { x: 0, y: 2 }
1607
+ - &BIG { r: 10 }
1608
+ - &SMALL { r: 1 }
1609
+
1610
+ # All the following maps are equal:
1611
+
1612
+ - # Explicit keys
1613
+ x: 1
1614
+ y: 2
1615
+ r: 10
1616
+ label: center/big
1617
+
1618
+ - # Merge one map
1619
+ << : *CENTER
1620
+ r: 10
1621
+ label: center/big
1622
+
1623
+ - # Merge multiple maps
1624
+ << : [ *CENTER, *BIG ]
1625
+ label: center/big
1626
+
1627
+ - # Override
1628
+ << : [ *BIG, *LEFT, *SMALL ]
1629
+ x: 1
1630
+ label: center/big
1631
+
1632
+ ruby-setup: |
1633
+ center = { 'x' => 1, 'y' => 2 }
1634
+ left = { 'x' => 0, 'y' => 2 }
1635
+ big = { 'r' => 10 }
1636
+ small = { 'r' => 1 }
1637
+ node1 = { 'x' => 1, 'y' => 2, 'r' => 10, 'label' => 'center/big' }
1638
+ node2 = center.dup
1639
+ node2.update( { 'r' => 10, 'label' => 'center/big' } )
1640
+ node3 = big.dup
1641
+ node3.update( center )
1642
+ node3.update( { 'label' => 'center/big' } )
1643
+ node4 = small.dup
1644
+ node4.update( left )
1645
+ node4.update( big )
1646
+ node4.update( { 'x' => 1, 'label' => 'center/big' } )
1647
+
1648
+ ruby: |
1649
+ [
1650
+ center, left, big, small, node1, node2, node3, node4
1651
+ ]
1652
+
1653
+ ---
1654
+ test: Default key
1655
+ todo: true
1656
+ yaml: |
1657
+ --- # Old schema
1658
+ link with:
1659
+ - library1.dll
1660
+ - library2.dll
1661
+ --- # New schema
1662
+ link with:
1663
+ - = : library1.dll
1664
+ version: 1.2
1665
+ - = : library2.dll
1666
+ version: 2.3
1667
+ ruby: |
1668
+ y = YAML::Stream.new
1669
+ y.add( { 'link with' => [ 'library1.dll', 'library2.dll' ] } )
1670
+ obj_h = Hash[ 'version' => 1.2 ]
1671
+ obj_h.default = 'library1.dll'
1672
+ obj_h2 = Hash[ 'version' => 2.3 ]
1673
+ obj_h2.default = 'library2.dll'
1674
+ y.add( { 'link with' => [ obj_h, obj_h2 ] } )
1675
+ documents: 2
1676
+
1677
+ ---
1678
+ test: Special keys
1679
+ todo: true
1680
+ yaml: |
1681
+ "!": These three keys
1682
+ "&": had to be quoted
1683
+ "=": and are normal strings.
1684
+ # NOTE: the following node should NOT be serialized this way.
1685
+ encoded node :
1686
+ !special '!' : '!type'
1687
+ !special|canonical '&' : 12
1688
+ = : value
1689
+ # The proper way to serialize the above node is as follows:
1690
+ node : !!type &12 value
1691
+ ruby: |
1692
+ { '!' => 'These three keys', '&' => 'had to be quoted',
1693
+ '=' => 'and are normal strings.',
1694
+ 'encoded node' => YAML::PrivateType.new( 'type', 'value' ),
1695
+ 'node' => YAML::PrivateType.new( 'type', 'value' ) }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/YtsTypeTransfers.yml ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Strings
3
+ brief: >
4
+ Any group of characters beginning with an
5
+ alphabetic or numeric character is a string,
6
+ unless it belongs to one of the groups below
7
+ (such as an Integer or Time).
8
+ yaml: |
9
+ String
10
+ php: |
11
+ 'String'
12
+ ---
13
+ test: String characters
14
+ brief: >
15
+ A string can contain any alphabetic or
16
+ numeric character, along with many
17
+ punctuation characters, including the
18
+ period, dash, space, quotes, exclamation, and
19
+ question mark.
20
+ yaml: |
21
+ - What's Yaml?
22
+ - It's for writing data structures in plain text.
23
+ - And?
24
+ - And what? That's not good enough for you?
25
+ - No, I mean, "And what about Yaml?"
26
+ - Oh, oh yeah. Uh.. Yaml for Ruby.
27
+ php: |
28
+ array(
29
+ "What's Yaml?",
30
+ "It's for writing data structures in plain text.",
31
+ "And?",
32
+ "And what? That's not good enough for you?",
33
+ "No, I mean, \"And what about Yaml?\"",
34
+ "Oh, oh yeah. Uh.. Yaml for Ruby."
35
+ )
36
+ ---
37
+ test: Indicators in Strings
38
+ brief: >
39
+ Be careful using indicators in strings. In particular,
40
+ the comma, colon, and pound sign must be used carefully.
41
+ yaml: |
42
+ the colon followed by space is an indicator: but is a string:right here
43
+ same for the pound sign: here we have it#in a string
44
+ the comma can, honestly, be used in most cases: [ but not in, inline collections ]
45
+ php: |
46
+ array(
47
+ 'the colon followed by space is an indicator' => 'but is a string:right here',
48
+ 'same for the pound sign' => 'here we have it#in a string',
49
+ 'the comma can, honestly, be used in most cases' => array('but not in', 'inline collections')
50
+ )
51
+ ---
52
+ test: Forcing Strings
53
+ brief: >
54
+ Any YAML type can be forced into a string using the
55
+ explicit !str method.
56
+ yaml: |
57
+ date string: !str 2001-08-01
58
+ number string: !str 192
59
+ php: |
60
+ array(
61
+ 'date string' => '2001-08-01',
62
+ 'number string' => '192'
63
+ )
64
+ ---
65
+ test: Single-quoted Strings
66
+ brief: >
67
+ You can also enclose your strings within single quotes,
68
+ which allows use of slashes, colons, and other indicators
69
+ freely. Inside single quotes, you can represent a single
70
+ quote in your string by using two single quotes next to
71
+ each other.
72
+ yaml: |
73
+ all my favorite symbols: '#:!/%.)'
74
+ a few i hate: '&(*'
75
+ why do i hate them?: 'it''s very hard to explain'
76
+ entities: '&pound; me'
77
+ php: |
78
+ array(
79
+ 'all my favorite symbols' => '#:!/%.)',
80
+ 'a few i hate' => '&(*',
81
+ 'why do i hate them?' => 'it\'s very hard to explain',
82
+ 'entities' => '&pound; me'
83
+ )
84
+ ---
85
+ test: Double-quoted Strings
86
+ brief: >
87
+ Enclosing strings in double quotes allows you
88
+ to use escapings to represent ASCII and
89
+ Unicode characters.
90
+ yaml: |
91
+ i know where i want my line breaks: "one here\nand another here\n"
92
+ php: |
93
+ array(
94
+ 'i know where i want my line breaks' => "one here\nand another here\n"
95
+ )
96
+ ---
97
+ test: Multi-line Quoted Strings
98
+ todo: true
99
+ brief: >
100
+ Both single- and double-quoted strings may be
101
+ carried on to new lines in your YAML document.
102
+ They must be indented a step and indentation
103
+ is interpreted as a single space.
104
+ yaml: |
105
+ i want a long string: "so i'm going to
106
+ let it go on and on to other lines
107
+ until i end it with a quote."
108
+ php: |
109
+ array('i want a long string' => "so i'm going to ".
110
+ "let it go on and on to other lines ".
111
+ "until i end it with a quote."
112
+ )
113
+
114
+ ---
115
+ test: Plain scalars
116
+ todo: true
117
+ brief: >
118
+ Unquoted strings may also span multiple lines, if they
119
+ are free of YAML space indicators and indented.
120
+ yaml: |
121
+ - My little toe is broken in two places;
122
+ - I'm crazy to have skied this way;
123
+ - I'm not the craziest he's seen, since there was always the German guy
124
+ who skied for 3 hours on a broken shin bone (just below the kneecap);
125
+ - Nevertheless, second place is respectable, and he doesn't
126
+ recommend going for the record;
127
+ - He's going to put my foot in plaster for a month;
128
+ - This would impair my skiing ability somewhat for the
129
+ duration, as can be imagined.
130
+ php: |
131
+ array(
132
+ "My little toe is broken in two places;",
133
+ "I'm crazy to have skied this way;",
134
+ "I'm not the craziest he's seen, since there was always ".
135
+ "the German guy who skied for 3 hours on a broken shin ".
136
+ "bone (just below the kneecap);",
137
+ "Nevertheless, second place is respectable, and he doesn't ".
138
+ "recommend going for the record;",
139
+ "He's going to put my foot in plaster for a month;",
140
+ "This would impair my skiing ability somewhat for the duration, ".
141
+ "as can be imagined."
142
+ )
143
+ ---
144
+ test: 'Null'
145
+ brief: >
146
+ You can use the tilde '~' character for a null value.
147
+ yaml: |
148
+ name: Mr. Show
149
+ hosted by: Bob and David
150
+ date of next season: ~
151
+ php: |
152
+ array(
153
+ 'name' => 'Mr. Show',
154
+ 'hosted by' => 'Bob and David',
155
+ 'date of next season' => null
156
+ )
157
+ ---
158
+ test: Boolean
159
+ brief: >
160
+ You can use 'true' and 'false' for Boolean values.
161
+ yaml: |
162
+ Is Gus a Liar?: true
163
+ Do I rely on Gus for Sustenance?: false
164
+ php: |
165
+ array(
166
+ 'Is Gus a Liar?' => true,
167
+ 'Do I rely on Gus for Sustenance?' => false
168
+ )
169
+ ---
170
+ test: Integers
171
+ dump_skip: true
172
+ brief: >
173
+ An integer is a series of numbers, optionally
174
+ starting with a positive or negative sign. Integers
175
+ may also contain commas for readability.
176
+ yaml: |
177
+ zero: 0
178
+ simple: 12
179
+ one-thousand: 1,000
180
+ negative one-thousand: -1,000
181
+ php: |
182
+ array(
183
+ 'zero' => 0,
184
+ 'simple' => 12,
185
+ 'one-thousand' => 1000,
186
+ 'negative one-thousand' => -1000
187
+ )
188
+ ---
189
+ test: Integers as Map Keys
190
+ brief: >
191
+ An integer can be used a dictionary key.
192
+ yaml: |
193
+ 1: one
194
+ 2: two
195
+ 3: three
196
+ php: |
197
+ array(
198
+ 1 => 'one',
199
+ 2 => 'two',
200
+ 3 => 'three'
201
+ )
202
+ ---
203
+ test: Floats
204
+ dump_skip: true
205
+ brief: >
206
+ Floats are represented by numbers with decimals,
207
+ allowing for scientific notation, as well as
208
+ positive and negative infinity and "not a number."
209
+ yaml: |
210
+ a simple float: 2.00
211
+ larger float: 1,000.09
212
+ scientific notation: 1.00009e+3
213
+ php: |
214
+ array(
215
+ 'a simple float' => 2.0,
216
+ 'larger float' => 1000.09,
217
+ 'scientific notation' => 1000.09
218
+ )
219
+ ---
220
+ test: Time
221
+ todo: true
222
+ brief: >
223
+ You can represent timestamps by using
224
+ ISO8601 format, or a variation which
225
+ allows spaces between the date, time and
226
+ time zone.
227
+ yaml: |
228
+ iso8601: 2001-12-14t21:59:43.10-05:00
229
+ space separated: 2001-12-14 21:59:43.10 -05:00
230
+ php: |
231
+ array(
232
+ 'iso8601' => mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ),
233
+ 'space separated' => mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" )
234
+ )
235
+ ---
236
+ test: Date
237
+ todo: true
238
+ brief: >
239
+ A date can be represented by its year,
240
+ month and day in ISO8601 order.
241
+ yaml: |
242
+ 1976-07-31
243
+ php: |
244
+ date( 1976, 7, 31 )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/embededPhp.yml ADDED
@@ -0,0 +1 @@
 
1
+ value: <?php echo 1 + 2 + 3 ?>
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/escapedCharacters.yml ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ test: outside double quotes
2
+ yaml: |
3
+ \0 \ \a \b \n
4
+ php: |
5
+ "\\0 \\ \\a \\b \\n"
6
+ ---
7
+ test: null
8
+ yaml: |
9
+ "\0"
10
+ php: |
11
+ "\x00"
12
+ ---
13
+ test: bell
14
+ yaml: |
15
+ "\a"
16
+ php: |
17
+ "\x07"
18
+ ---
19
+ test: backspace
20
+ yaml: |
21
+ "\b"
22
+ php: |
23
+ "\x08"
24
+ ---
25
+ test: horizontal tab (1)
26
+ yaml: |
27
+ "\t"
28
+ php: |
29
+ "\x09"
30
+ ---
31
+ test: horizontal tab (2)
32
+ yaml: |
33
+ "\ "
34
+ php: |
35
+ "\x09"
36
+ ---
37
+ test: line feed
38
+ yaml: |
39
+ "\n"
40
+ php: |
41
+ "\x0a"
42
+ ---
43
+ test: vertical tab
44
+ yaml: |
45
+ "\v"
46
+ php: |
47
+ "\x0b"
48
+ ---
49
+ test: form feed
50
+ yaml: |
51
+ "\f"
52
+ php: |
53
+ "\x0c"
54
+ ---
55
+ test: carriage return
56
+ yaml: |
57
+ "\r"
58
+ php: |
59
+ "\x0d"
60
+ ---
61
+ test: escape
62
+ yaml: |
63
+ "\e"
64
+ php: |
65
+ "\x1b"
66
+ ---
67
+ test: space
68
+ yaml: |
69
+ "\ "
70
+ php: |
71
+ "\x20"
72
+ ---
73
+ test: slash
74
+ yaml: |
75
+ "\/"
76
+ php: |
77
+ "\x2f"
78
+ ---
79
+ test: backslash
80
+ yaml: |
81
+ "\\"
82
+ php: |
83
+ "\\"
84
+ ---
85
+ test: Unicode next line
86
+ yaml: |
87
+ "\N"
88
+ php: |
89
+ "\xc2\x85"
90
+ ---
91
+ test: Unicode non-breaking space
92
+ yaml: |
93
+ "\_"
94
+ php: |
95
+ "\xc2\xa0"
96
+ ---
97
+ test: Unicode line separator
98
+ yaml: |
99
+ "\L"
100
+ php: |
101
+ "\xe2\x80\xa8"
102
+ ---
103
+ test: Unicode paragraph separator
104
+ yaml: |
105
+ "\P"
106
+ php: |
107
+ "\xe2\x80\xa9"
108
+ ---
109
+ test: Escaped 8-bit Unicode
110
+ yaml: |
111
+ "\x42"
112
+ php: |
113
+ "B"
114
+ ---
115
+ test: Escaped 16-bit Unicode
116
+ yaml: |
117
+ "\u20ac"
118
+ php: |
119
+ "\xe2\x82\xac"
120
+ ---
121
+ test: Escaped 32-bit Unicode
122
+ yaml: |
123
+ "\U00000043"
124
+ php: |
125
+ "C"
126
+ ---
127
+ test: Example 5.13 Escaped Characters
128
+ note: |
129
+ Currently throws an error parsing first line. Maybe Symfony Yaml doesn't support
130
+ continuation of string across multiple lines? Keeping test here but disabled.
131
+ todo: true
132
+ yaml: |
133
+ "Fun with \\
134
+ \" \a \b \e \f \
135
+ \n \r \t \v \0 \
136
+ \ \_ \N \L \P \
137
+ \x41 \u0041 \U00000041"
138
+ php: |
139
+ "Fun with \x5C\n\x22 \x07 \x08 \x1B \x0C\n\x0A \x0D \x09 \x0B \x00\n\x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9\nA A A"
140
+ ---
141
+ test: Double quotes with a line feed
142
+ yaml: |
143
+ { double: "some value\n \"some quoted string\" and 'some single quotes one'" }
144
+ php: |
145
+ array(
146
+ 'double' => "some value\n \"some quoted string\" and 'some single quotes one'"
147
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/index.yml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ - escapedCharacters
2
+ - sfComments
3
+ - sfCompact
4
+ - sfTests
5
+ - sfObjects
6
+ - sfMergeKey
7
+ - sfQuotes
8
+ - YtsAnchorAlias
9
+ - YtsBasicTests
10
+ - YtsBlockMapping
11
+ - YtsDocumentSeparator
12
+ - YtsErrorTests
13
+ - YtsFlowCollections
14
+ - YtsFoldedScalars
15
+ - YtsNullsAndEmpties
16
+ - YtsSpecificationExamples
17
+ - YtsTypeTransfers
18
+ - unindentedCollections
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfComments.yml ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Comments at the end of a line
3
+ brief: >
4
+ Comments at the end of a line
5
+ yaml: |
6
+ ex1: "foo # bar"
7
+ ex2: "foo # bar" # comment
8
+ ex3: 'foo # bar' # comment
9
+ ex4: foo # comment
10
+ php: |
11
+ array('ex1' => 'foo # bar', 'ex2' => 'foo # bar', 'ex3' => 'foo # bar', 'ex4' => 'foo')
12
+ ---
13
+ test: Comments in the middle
14
+ brief: >
15
+ Comments in the middle
16
+ yaml: |
17
+ foo:
18
+ # some comment
19
+ # some comment
20
+ bar: foo
21
+ # some comment
22
+ # some comment
23
+ php: |
24
+ array('foo' => array('bar' => 'foo'))
25
+ ---
26
+ test: Comments on a hash line
27
+ brief: >
28
+ Comments on a hash line
29
+ yaml: |
30
+ foo: # a comment
31
+ foo: bar # a comment
32
+ php: |
33
+ array('foo' => array('foo' => 'bar'))
34
+ ---
35
+ test: 'Value starting with a #'
36
+ brief: >
37
+ 'Value starting with a #'
38
+ yaml: |
39
+ foo: '#bar'
40
+ php: |
41
+ array('foo' => '#bar')
42
+ ---
43
+ test: Document starting with a comment and a separator
44
+ brief: >
45
+ Commenting before document start is allowed
46
+ yaml: |
47
+ # document comment
48
+ ---
49
+ foo: bar # a comment
50
+ php: |
51
+ array('foo' => 'bar')
52
+ ---
53
+ test: Comment containing a colon on a hash line
54
+ brief: >
55
+ Comment containing a colon on a scalar line
56
+ yaml: 'foo # comment: this is also part of the comment'
57
+ php: |
58
+ 'foo'
59
+ ---
60
+ test: 'Hash key containing a #'
61
+ brief: >
62
+ 'Hash key containing a #'
63
+ yaml: 'foo#bar: baz'
64
+ php: |
65
+ array('foo#bar' => 'baz')
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfCompact.yml ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Compact notation
3
+ brief: |
4
+ Compact notation for sets of mappings with single element
5
+ yaml: |
6
+ ---
7
+ # products purchased
8
+ - item : Super Hoop
9
+ - item : Basketball
10
+ quantity: 1
11
+ - item:
12
+ name: Big Shoes
13
+ nick: Biggies
14
+ quantity: 1
15
+ php: |
16
+ array (
17
+ array (
18
+ 'item' => 'Super Hoop',
19
+ ),
20
+ array (
21
+ 'item' => 'Basketball',
22
+ 'quantity' => 1,
23
+ ),
24
+ array (
25
+ 'item' => array(
26
+ 'name' => 'Big Shoes',
27
+ 'nick' => 'Biggies'
28
+ ),
29
+ 'quantity' => 1
30
+ )
31
+ )
32
+ ---
33
+ test: Compact notation combined with inline notation
34
+ brief: |
35
+ Combinations of compact and inline notation are allowed
36
+ yaml: |
37
+ ---
38
+ items:
39
+ - { item: Super Hoop, quantity: 1 }
40
+ - [ Basketball, Big Shoes ]
41
+ php: |
42
+ array (
43
+ 'items' => array (
44
+ array (
45
+ 'item' => 'Super Hoop',
46
+ 'quantity' => 1,
47
+ ),
48
+ array (
49
+ 'Basketball',
50
+ 'Big Shoes'
51
+ )
52
+ )
53
+ )
54
+ --- %YAML:1.0
55
+ test: Compact notation
56
+ brief: |
57
+ Compact notation for sets of mappings with single element
58
+ yaml: |
59
+ ---
60
+ # products purchased
61
+ - item : Super Hoop
62
+ - item : Basketball
63
+ quantity: 1
64
+ - item:
65
+ name: Big Shoes
66
+ nick: Biggies
67
+ quantity: 1
68
+ php: |
69
+ array (
70
+ array (
71
+ 'item' => 'Super Hoop',
72
+ ),
73
+ array (
74
+ 'item' => 'Basketball',
75
+ 'quantity' => 1,
76
+ ),
77
+ array (
78
+ 'item' => array(
79
+ 'name' => 'Big Shoes',
80
+ 'nick' => 'Biggies'
81
+ ),
82
+ 'quantity' => 1
83
+ )
84
+ )
85
+ ---
86
+ test: Compact notation combined with inline notation
87
+ brief: |
88
+ Combinations of compact and inline notation are allowed
89
+ yaml: |
90
+ ---
91
+ items:
92
+ - { item: Super Hoop, quantity: 1 }
93
+ - [ Basketball, Big Shoes ]
94
+ php: |
95
+ array (
96
+ 'items' => array (
97
+ array (
98
+ 'item' => 'Super Hoop',
99
+ 'quantity' => 1,
100
+ ),
101
+ array (
102
+ 'Basketball',
103
+ 'Big Shoes'
104
+ )
105
+ )
106
+ )
107
+ --- %YAML:1.0
108
+ test: Compact notation
109
+ brief: |
110
+ Compact notation for sets of mappings with single element
111
+ yaml: |
112
+ ---
113
+ # products purchased
114
+ - item : Super Hoop
115
+ - item : Basketball
116
+ quantity: 1
117
+ - item:
118
+ name: Big Shoes
119
+ nick: Biggies
120
+ quantity: 1
121
+ php: |
122
+ array (
123
+ array (
124
+ 'item' => 'Super Hoop',
125
+ ),
126
+ array (
127
+ 'item' => 'Basketball',
128
+ 'quantity' => 1,
129
+ ),
130
+ array (
131
+ 'item' => array(
132
+ 'name' => 'Big Shoes',
133
+ 'nick' => 'Biggies'
134
+ ),
135
+ 'quantity' => 1
136
+ )
137
+ )
138
+ ---
139
+ test: Compact notation combined with inline notation
140
+ brief: |
141
+ Combinations of compact and inline notation are allowed
142
+ yaml: |
143
+ ---
144
+ items:
145
+ - { item: Super Hoop, quantity: 1 }
146
+ - [ Basketball, Big Shoes ]
147
+ php: |
148
+ array (
149
+ 'items' => array (
150
+ array (
151
+ 'item' => 'Super Hoop',
152
+ 'quantity' => 1,
153
+ ),
154
+ array (
155
+ 'Basketball',
156
+ 'Big Shoes'
157
+ )
158
+ )
159
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Simple In Place Substitution
3
+ brief: >
4
+ If you want to reuse an entire alias, only overwriting what is different
5
+ you can use a << in place substitution. This is not part of the official
6
+ YAML spec, but a widely implemented extension. See the following URL for
7
+ details: http://yaml.org/type/merge.html
8
+ yaml: |
9
+ foo: &foo
10
+ a: Steve
11
+ b: Clark
12
+ c: Brian
13
+ bar: &bar
14
+ <<: *foo
15
+ x: Oren
16
+ foo2: &foo2
17
+ a: Ballmer
18
+ ding: &dong [ fi, fei, fo, fam]
19
+ check:
20
+ <<:
21
+ - *foo
22
+ - *dong
23
+ isit: tested
24
+ head:
25
+ <<: [ *foo , *dong , *foo2 ]
26
+ php: |
27
+ array('foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian'), 'bar' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'x' => 'Oren'), 'foo2' => array('a' => 'Ballmer'), 'ding' => array('fi', 'fei', 'fo', 'fam'), 'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'), 'head' => array('a' => 'Ballmer', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam'))
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfObjects.yml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Objects
3
+ brief: >
4
+ Comments at the end of a line
5
+ yaml: |
6
+ ex1: "foo # bar"
7
+ ex2: "foo # bar" # comment
8
+ ex3: 'foo # bar' # comment
9
+ ex4: foo # comment
10
+ php: |
11
+ array('ex1' => 'foo # bar', 'ex2' => 'foo # bar', 'ex3' => 'foo # bar', 'ex4' => 'foo')
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfQuotes.yml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Some characters at the beginning of a string must be escaped
3
+ brief: >
4
+ Some characters at the beginning of a string must be escaped
5
+ yaml: |
6
+ foo: | bar
7
+ php: |
8
+ array('foo' => '| bar')
9
+ ---
10
+ test: A key can be a quoted string
11
+ brief: >
12
+ A key can be a quoted string
13
+ yaml: |
14
+ "foo1": bar
15
+ 'foo2': bar
16
+ "foo \" bar": bar
17
+ 'foo '' bar': bar
18
+ 'foo3: ': bar
19
+ "foo4: ": bar
20
+ foo5: { "foo \" bar: ": bar, 'foo '' bar: ': bar }
21
+ php: |
22
+ array(
23
+ 'foo1' => 'bar',
24
+ 'foo2' => 'bar',
25
+ 'foo " bar' => 'bar',
26
+ 'foo \' bar' => 'bar',
27
+ 'foo3: ' => 'bar',
28
+ 'foo4: ' => 'bar',
29
+ 'foo5' => array(
30
+ 'foo " bar: ' => 'bar',
31
+ 'foo \' bar: ' => 'bar',
32
+ ),
33
+ )
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Multiple quoted string on one line
3
+ brief: >
4
+ Multiple quoted string on one line
5
+ yaml: |
6
+ stripped_title: { name: "foo bar", help: "bar foo" }
7
+ php: |
8
+ array('stripped_title' => array('name' => 'foo bar', 'help' => 'bar foo'))
9
+ ---
10
+ test: Empty sequence
11
+ yaml: |
12
+ foo: [ ]
13
+ php: |
14
+ array('foo' => array())
15
+ ---
16
+ test: Empty value
17
+ yaml: |
18
+ foo:
19
+ php: |
20
+ array('foo' => null)
21
+ ---
22
+ test: Inline string parsing
23
+ brief: >
24
+ Inline string parsing
25
+ yaml: |
26
+ test: ['complex: string', 'another [string]']
27
+ php: |
28
+ array('test' => array('complex: string', 'another [string]'))
29
+ ---
30
+ test: Boolean
31
+ brief: >
32
+ Boolean
33
+ yaml: |
34
+ - false
35
+ - true
36
+ - null
37
+ - ~
38
+ - 'false'
39
+ - 'true'
40
+ - 'null'
41
+ - '~'
42
+ php: |
43
+ array(
44
+ false,
45
+ true,
46
+ null,
47
+ null,
48
+ 'false',
49
+ 'true',
50
+ 'null',
51
+ '~',
52
+ )
53
+ ---
54
+ test: Empty lines in folded blocks
55
+ brief: >
56
+ Empty lines in folded blocks
57
+ yaml: |
58
+ foo:
59
+ bar: |
60
+ foo
61
+
62
+
63
+
64
+ bar
65
+ php: |
66
+ array('foo' => array('bar' => "foo\n\n\n \nbar\n"))
67
+ ---
68
+ test: IP addresses
69
+ brief: >
70
+ IP addresses
71
+ yaml: |
72
+ foo: 10.0.0.2
73
+ php: |
74
+ array('foo' => '10.0.0.2')
75
+ ---
76
+ test: A sequence with an embedded mapping
77
+ brief: >
78
+ A sequence with an embedded mapping
79
+ yaml: |
80
+ - foo
81
+ - bar: { bar: foo }
82
+ php: |
83
+ array('foo', array('bar' => array('bar' => 'foo')))
84
+ ---
85
+ test: A sequence with an unordered array
86
+ brief: >
87
+ A sequence with an unordered array
88
+ yaml: |
89
+ 1: foo
90
+ 0: bar
91
+ php: |
92
+ array(1 => 'foo', 0 => 'bar')
93
+ ---
94
+ test: Octal
95
+ brief: as in spec example 2.19, octal value is converted
96
+ yaml: |
97
+ foo: 0123
98
+ php: |
99
+ array('foo' => 83)
100
+ ---
101
+ test: Octal strings
102
+ brief: Octal notation in a string must remain a string
103
+ yaml: |
104
+ foo: "0123"
105
+ php: |
106
+ array('foo' => '0123')
107
+ ---
108
+ test: Octal strings
109
+ brief: Octal notation in a string must remain a string
110
+ yaml: |
111
+ foo: '0123'
112
+ php: |
113
+ array('foo' => '0123')
114
+ ---
115
+ test: Octal strings
116
+ brief: Octal notation in a string must remain a string
117
+ yaml: |
118
+ foo: |
119
+ 0123
120
+ php: |
121
+ array('foo' => "0123\n")
122
+ ---
123
+ test: Document as a simple hash
124
+ brief: Document as a simple hash
125
+ yaml: |
126
+ { foo: bar }
127
+ php: |
128
+ array('foo' => 'bar')
129
+ ---
130
+ test: Document as a simple array
131
+ brief: Document as a simple array
132
+ yaml: |
133
+ [ foo, bar ]
134
+ php: |
135
+ array('foo', 'bar')
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/Fixtures/unindentedCollections.yml ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- %YAML:1.0
2
+ test: Unindented collection
3
+ brief: >
4
+ Unindented collection
5
+ yaml: |
6
+ collection:
7
+ - item1
8
+ - item2
9
+ - item3
10
+ php: |
11
+ array('collection' => array('item1', 'item2', 'item3'))
12
+ ---
13
+ test: Nested unindented collection (two levels)
14
+ brief: >
15
+ Nested unindented collection
16
+ yaml: |
17
+ collection:
18
+ key:
19
+ - a
20
+ - b
21
+ - c
22
+ php: |
23
+ array('collection' => array('key' => array('a', 'b', 'c')))
24
+ ---
25
+ test: Nested unindented collection (three levels)
26
+ brief: >
27
+ Nested unindented collection
28
+ yaml: |
29
+ collection:
30
+ key:
31
+ subkey:
32
+ - one
33
+ - two
34
+ - three
35
+ php: |
36
+ array('collection' => array('key' => array('subkey' => array('one', 'two', 'three'))))
37
+ ---
38
+ test: Key/value after unindented collection (1)
39
+ brief: >
40
+ Key/value after unindented collection (1)
41
+ yaml: |
42
+ collection:
43
+ key:
44
+ - a
45
+ - b
46
+ - c
47
+ foo: bar
48
+ php: |
49
+ array('collection' => array('key' => array('a', 'b', 'c')), 'foo' => 'bar')
50
+ ---
51
+ test: Key/value after unindented collection (at the same level)
52
+ brief: >
53
+ Key/value after unindented collection
54
+ yaml: |
55
+ collection:
56
+ key:
57
+ - a
58
+ - b
59
+ - c
60
+ foo: bar
61
+ php: |
62
+ array('collection' => array('key' => array('a', 'b', 'c'), 'foo' => 'bar'))
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/InlineTest.php ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Tests;
13
+
14
+ use Symfony\Component\Yaml\Inline;
15
+
16
+ class InlineTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testParse()
19
+ {
20
+ foreach ($this->getTestsForParse() as $yaml => $value) {
21
+ $this->assertSame($value, Inline::parse($yaml), sprintf('::parse() converts an inline YAML to a PHP structure (%s)', $yaml));
22
+ }
23
+ }
24
+
25
+ public function testDump()
26
+ {
27
+ $testsForDump = $this->getTestsForDump();
28
+
29
+ foreach ($testsForDump as $yaml => $value) {
30
+ $this->assertEquals($yaml, Inline::dump($value), sprintf('::dump() converts a PHP structure to an inline YAML (%s)', $yaml));
31
+ }
32
+
33
+ foreach ($this->getTestsForParse() as $value) {
34
+ $this->assertEquals($value, Inline::parse(Inline::dump($value)), 'check consistency');
35
+ }
36
+
37
+ foreach ($testsForDump as $value) {
38
+ $this->assertEquals($value, Inline::parse(Inline::dump($value)), 'check consistency');
39
+ }
40
+ }
41
+
42
+ public function testDumpNumericValueWithLocale()
43
+ {
44
+ $locale = setlocale(LC_NUMERIC, 0);
45
+ if (false === $locale) {
46
+ $this->markTestSkipped('Your platform does not support locales.');
47
+ }
48
+
49
+ $required_locales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252');
50
+ if (false === setlocale(LC_ALL, $required_locales)) {
51
+ $this->markTestSkipped('Could not set any of required locales: '.implode(", ", $required_locales));
52
+ }
53
+
54
+ $this->assertEquals('1.2', Inline::dump(1.2));
55
+ $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0)));
56
+
57
+ setlocale(LC_ALL, $locale);
58
+ }
59
+
60
+ public function testHashStringsResemblingExponentialNumericsShouldNotBeChangedToINF()
61
+ {
62
+ $value = '686e444';
63
+
64
+ $this->assertSame($value, Inline::parse(Inline::dump($value)));
65
+ }
66
+
67
+ /**
68
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
69
+ */
70
+ public function testParseScalarWithIncorrectlyQuotedStringShouldThrowException()
71
+ {
72
+ $value = "'don't do somthin' like that'";
73
+ Inline::parse($value);
74
+ }
75
+
76
+ /**
77
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
78
+ */
79
+ public function testParseScalarWithIncorrectlyDoubleQuotedStringShouldThrowException()
80
+ {
81
+ $value = '"don"t do somthin" like that"';
82
+ Inline::parse($value);
83
+ }
84
+
85
+ /**
86
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
87
+ */
88
+ public function testParseInvalidMappingKeyShouldThrowException()
89
+ {
90
+ $value = '{ "foo " bar": "bar" }';
91
+ Inline::parse($value);
92
+ }
93
+
94
+ /**
95
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
96
+ */
97
+ public function testParseInvalidMappingShouldThrowException()
98
+ {
99
+ Inline::parse('[foo] bar');
100
+ }
101
+
102
+ /**
103
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
104
+ */
105
+ public function testParseInvalidSequenceShouldThrowException()
106
+ {
107
+ Inline::parse('{ foo: bar } bar');
108
+ }
109
+
110
+ public function testParseScalarWithCorrectlyQuotedStringShouldReturnString()
111
+ {
112
+ $value = "'don''t do somthin'' like that'";
113
+ $expect = "don't do somthin' like that";
114
+
115
+ $this->assertSame($expect, Inline::parseScalar($value));
116
+ }
117
+
118
+ protected function getTestsForParse()
119
+ {
120
+ return array(
121
+ '' => '',
122
+ 'null' => null,
123
+ 'false' => false,
124
+ 'true' => true,
125
+ '12' => 12,
126
+ '-12' => -12,
127
+ '"quoted string"' => 'quoted string',
128
+ "'quoted string'" => 'quoted string',
129
+ '12.30e+02' => 12.30e+02,
130
+ '0x4D2' => 0x4D2,
131
+ '02333' => 02333,
132
+ '.Inf' => -log(0),
133
+ '-.Inf' => log(0),
134
+ "'686e444'" => '686e444',
135
+ '686e444' => 646e444,
136
+ '123456789123456789123456789123456789' => '123456789123456789123456789123456789',
137
+ '"foo\r\nbar"' => "foo\r\nbar",
138
+ "'foo#bar'" => 'foo#bar',
139
+ "'foo # bar'" => 'foo # bar',
140
+ "'#cfcfcf'" => '#cfcfcf',
141
+ '::form_base.html.twig' => '::form_base.html.twig',
142
+
143
+ '2007-10-30' => mktime(0, 0, 0, 10, 30, 2007),
144
+ '2007-10-30T02:59:43Z' => gmmktime(2, 59, 43, 10, 30, 2007),
145
+ '2007-10-30 02:59:43 Z' => gmmktime(2, 59, 43, 10, 30, 2007),
146
+ '1960-10-30 02:59:43 Z' => gmmktime(2, 59, 43, 10, 30, 1960),
147
+ '1730-10-30T02:59:43Z' => gmmktime(2, 59, 43, 10, 30, 1730),
148
+
149
+ '"a \\"string\\" with \'quoted strings inside\'"' => 'a "string" with \'quoted strings inside\'',
150
+ "'a \"string\" with ''quoted strings inside'''" => 'a "string" with \'quoted strings inside\'',
151
+
152
+ // sequences
153
+ // urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon
154
+ '[foo, http://urls.are/no/mappings, false, null, 12]' => array('foo', 'http://urls.are/no/mappings', false, null, 12),
155
+ '[ foo , bar , false , null , 12 ]' => array('foo', 'bar', false, null, 12),
156
+ '[\'foo,bar\', \'foo bar\']' => array('foo,bar', 'foo bar'),
157
+
158
+ // mappings
159
+ '{foo:bar,bar:foo,false:false,null:null,integer:12}' => array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12),
160
+ '{ foo : bar, bar : foo, false : false, null : null, integer : 12 }' => array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12),
161
+ '{foo: \'bar\', bar: \'foo: bar\'}' => array('foo' => 'bar', 'bar' => 'foo: bar'),
162
+ '{\'foo\': \'bar\', "bar": \'foo: bar\'}' => array('foo' => 'bar', 'bar' => 'foo: bar'),
163
+ '{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}' => array('foo\'' => 'bar', "bar\"" => 'foo: bar'),
164
+ '{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}' => array('foo: ' => 'bar', "bar: " => 'foo: bar'),
165
+
166
+ // nested sequences and mappings
167
+ '[foo, [bar, foo]]' => array('foo', array('bar', 'foo')),
168
+ '[foo, {bar: foo}]' => array('foo', array('bar' => 'foo')),
169
+ '{ foo: {bar: foo} }' => array('foo' => array('bar' => 'foo')),
170
+ '{ foo: [bar, foo] }' => array('foo' => array('bar', 'foo')),
171
+
172
+ '[ foo, [ bar, foo ] ]' => array('foo', array('bar', 'foo')),
173
+
174
+ '[{ foo: {bar: foo} }]' => array(array('foo' => array('bar' => 'foo'))),
175
+
176
+ '[foo, [bar, [foo, [bar, foo]], foo]]' => array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo')),
177
+
178
+ '[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]' => array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo'))),
179
+
180
+ '[foo, bar: { foo: bar }]' => array('foo', '1' => array('bar' => array('foo' => 'bar'))),
181
+ '[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']' => array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%',), true, '@service_container',),
182
+ );
183
+ }
184
+
185
+ protected function getTestsForDump()
186
+ {
187
+ return array(
188
+ 'null' => null,
189
+ 'false' => false,
190
+ 'true' => true,
191
+ '12' => 12,
192
+ "'quoted string'" => 'quoted string',
193
+ '12.30e+02' => 12.30e+02,
194
+ '1234' => 0x4D2,
195
+ '1243' => 02333,
196
+ '.Inf' => -log(0),
197
+ '-.Inf' => log(0),
198
+ "'686e444'" => '686e444',
199
+ '"foo\r\nbar"' => "foo\r\nbar",
200
+ "'foo#bar'" => 'foo#bar',
201
+ "'foo # bar'" => 'foo # bar',
202
+ "'#cfcfcf'" => '#cfcfcf',
203
+
204
+ "'a \"string\" with ''quoted strings inside'''" => 'a "string" with \'quoted strings inside\'',
205
+
206
+ "'-dash'" => '-dash',
207
+ "'-'" => '-',
208
+
209
+ // sequences
210
+ '[foo, bar, false, null, 12]' => array('foo', 'bar', false, null, 12),
211
+ '[\'foo,bar\', \'foo bar\']' => array('foo,bar', 'foo bar'),
212
+
213
+ // mappings
214
+ '{ foo: bar, bar: foo, \'false\': false, \'null\': null, integer: 12 }' => array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12),
215
+ '{ foo: bar, bar: \'foo: bar\' }' => array('foo' => 'bar', 'bar' => 'foo: bar'),
216
+
217
+ // nested sequences and mappings
218
+ '[foo, [bar, foo]]' => array('foo', array('bar', 'foo')),
219
+
220
+ '[foo, [bar, [foo, [bar, foo]], foo]]' => array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo')),
221
+
222
+ '{ foo: { bar: foo } }' => array('foo' => array('bar' => 'foo')),
223
+
224
+ '[foo, { bar: foo }]' => array('foo', array('bar' => 'foo')),
225
+
226
+ '[foo, { bar: foo, foo: [foo, { bar: foo }] }, [foo, { bar: foo }]]' => array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo'))),
227
+
228
+ '[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']' => array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%',), true, '@service_container',),
229
+ );
230
+ }
231
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/ParseExceptionTest.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Tests;
13
+
14
+ use Symfony\Component\Yaml\Exception\ParseException;
15
+ use Symfony\Component\Yaml\Yaml;
16
+
17
+ class ParseExceptionTest extends \PHPUnit_Framework_TestCase
18
+ {
19
+ public function testGetMessage()
20
+ {
21
+ $exception = new ParseException('Error message', 42, 'foo: bar', '/var/www/app/config.yml');
22
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
23
+ $message = 'Error message in "/var/www/app/config.yml" at line 42 (near "foo: bar")';
24
+ } else {
25
+ $message = 'Error message in "\\/var\\/www\\/app\\/config.yml" at line 42 (near "foo: bar")';
26
+ }
27
+
28
+ $this->assertEquals($message, $exception->getMessage());
29
+ }
30
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/ParserTest.php ADDED
@@ -0,0 +1,660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Tests;
13
+
14
+ use Symfony\Component\Yaml\Yaml;
15
+ use Symfony\Component\Yaml\Parser;
16
+
17
+ class ParserTest extends \PHPUnit_Framework_TestCase
18
+ {
19
+ protected $parser;
20
+
21
+ protected function setUp()
22
+ {
23
+ $this->parser = new Parser();
24
+ }
25
+
26
+ protected function tearDown()
27
+ {
28
+ $this->parser = null;
29
+ }
30
+
31
+ /**
32
+ * @dataProvider getDataFormSpecifications
33
+ */
34
+ public function testSpecifications($file, $expected, $yaml, $comment)
35
+ {
36
+ $this->assertEquals($expected, var_export($this->parser->parse($yaml), true), $comment);
37
+ }
38
+
39
+ public function getDataFormSpecifications()
40
+ {
41
+ $parser = new Parser();
42
+ $path = __DIR__.'/Fixtures';
43
+
44
+ $tests = array();
45
+ $files = $parser->parse(file_get_contents($path.'/index.yml'));
46
+ foreach ($files as $file) {
47
+ $yamls = file_get_contents($path.'/'.$file.'.yml');
48
+
49
+ // split YAMLs documents
50
+ foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) {
51
+ if (!$yaml) {
52
+ continue;
53
+ }
54
+
55
+ $test = $parser->parse($yaml);
56
+ if (isset($test['todo']) && $test['todo']) {
57
+ // TODO
58
+ } else {
59
+ eval('$expected = '.trim($test['php']).';');
60
+
61
+ $tests[] = array($file, var_export($expected, true), $test['yaml'], $test['test']);
62
+ }
63
+ }
64
+ }
65
+
66
+ return $tests;
67
+ }
68
+
69
+ public function testTabsInYaml()
70
+ {
71
+ // test tabs in YAML
72
+ $yamls = array(
73
+ "foo:\n bar",
74
+ "foo:\n bar",
75
+ "foo:\n bar",
76
+ "foo:\n bar",
77
+ );
78
+
79
+ foreach ($yamls as $yaml) {
80
+ try {
81
+ $content = $this->parser->parse($yaml);
82
+
83
+ $this->fail('YAML files must not contain tabs');
84
+ } catch (\Exception $e) {
85
+ $this->assertInstanceOf('\Exception', $e, 'YAML files must not contain tabs');
86
+ $this->assertEquals('A YAML file cannot contain tabs as indentation at line 2 (near "'.strpbrk($yaml, "\t").'").', $e->getMessage(), 'YAML files must not contain tabs');
87
+ }
88
+ }
89
+ }
90
+
91
+ public function testEndOfTheDocumentMarker()
92
+ {
93
+ $yaml = <<<EOF
94
+ --- %YAML:1.0
95
+ foo
96
+ ...
97
+ EOF;
98
+
99
+ $this->assertEquals('foo', $this->parser->parse($yaml));
100
+ }
101
+
102
+ public function getBlockChompingTests()
103
+ {
104
+ $tests = array();
105
+
106
+ $yaml = <<<'EOF'
107
+ foo: |-
108
+ one
109
+ two
110
+ bar: |-
111
+ one
112
+ two
113
+
114
+ EOF;
115
+ $expected = array(
116
+ 'foo' => "one\ntwo",
117
+ 'bar' => "one\ntwo",
118
+ );
119
+ $tests['Literal block chomping strip with single trailing newline'] = array($expected, $yaml);
120
+
121
+ $yaml = <<<'EOF'
122
+ foo: |-
123
+ one
124
+ two
125
+
126
+ bar: |-
127
+ one
128
+ two
129
+
130
+
131
+ EOF;
132
+ $expected = array(
133
+ 'foo' => "one\ntwo",
134
+ 'bar' => "one\ntwo",
135
+ );
136
+ $tests['Literal block chomping strip with multiple trailing newlines'] = array($expected, $yaml);
137
+
138
+ $yaml = <<<'EOF'
139
+ foo: |-
140
+ one
141
+ two
142
+ bar: |-
143
+ one
144
+ two
145
+ EOF;
146
+ $expected = array(
147
+ 'foo' => "one\ntwo",
148
+ 'bar' => "one\ntwo",
149
+ );
150
+ $tests['Literal block chomping strip without trailing newline'] = array($expected, $yaml);
151
+
152
+ $yaml = <<<'EOF'
153
+ foo: |
154
+ one
155
+ two
156
+ bar: |
157
+ one
158
+ two
159
+
160
+ EOF;
161
+ $expected = array(
162
+ 'foo' => "one\ntwo\n",
163
+ 'bar' => "one\ntwo\n",
164
+ );
165
+ $tests['Literal block chomping clip with single trailing newline'] = array($expected, $yaml);
166
+
167
+ $yaml = <<<'EOF'
168
+ foo: |
169
+ one
170
+ two
171
+
172
+ bar: |
173
+ one
174
+ two
175
+
176
+
177
+ EOF;
178
+ $expected = array(
179
+ 'foo' => "one\ntwo\n",
180
+ 'bar' => "one\ntwo\n",
181
+ );
182
+ $tests['Literal block chomping clip with multiple trailing newlines'] = array($expected, $yaml);
183
+
184
+ $yaml = <<<'EOF'
185
+ foo: |
186
+ one
187
+ two
188
+ bar: |
189
+ one
190
+ two
191
+ EOF;
192
+ $expected = array(
193
+ 'foo' => "one\ntwo\n",
194
+ 'bar' => "one\ntwo",
195
+ );
196
+ $tests['Literal block chomping clip without trailing newline'] = array($expected, $yaml);
197
+
198
+ $yaml = <<<'EOF'
199
+ foo: |+
200
+ one
201
+ two
202
+ bar: |+
203
+ one
204
+ two
205
+
206
+ EOF;
207
+ $expected = array(
208
+ 'foo' => "one\ntwo\n",
209
+ 'bar' => "one\ntwo\n",
210
+ );
211
+ $tests['Literal block chomping keep with single trailing newline'] = array($expected, $yaml);
212
+
213
+ $yaml = <<<'EOF'
214
+ foo: |+
215
+ one
216
+ two
217
+
218
+ bar: |+
219
+ one
220
+ two
221
+
222
+
223
+ EOF;
224
+ $expected = array(
225
+ 'foo' => "one\ntwo\n\n",
226
+ 'bar' => "one\ntwo\n\n",
227
+ );
228
+ $tests['Literal block chomping keep with multiple trailing newlines'] = array($expected, $yaml);
229
+
230
+ $yaml = <<<'EOF'
231
+ foo: |+
232
+ one
233
+ two
234
+ bar: |+
235
+ one
236
+ two
237
+ EOF;
238
+ $expected = array(
239
+ 'foo' => "one\ntwo\n",
240
+ 'bar' => "one\ntwo",
241
+ );
242
+ $tests['Literal block chomping keep without trailing newline'] = array($expected, $yaml);
243
+
244
+ $yaml = <<<'EOF'
245
+ foo: >-
246
+ one
247
+ two
248
+ bar: >-
249
+ one
250
+ two
251
+
252
+ EOF;
253
+ $expected = array(
254
+ 'foo' => "one two",
255
+ 'bar' => "one two",
256
+ );
257
+ $tests['Folded block chomping strip with single trailing newline'] = array($expected, $yaml);
258
+
259
+ $yaml = <<<'EOF'
260
+ foo: >-
261
+ one
262
+ two
263
+
264
+ bar: >-
265
+ one
266
+ two
267
+
268
+
269
+ EOF;
270
+ $expected = array(
271
+ 'foo' => "one two",
272
+ 'bar' => "one two",
273
+ );
274
+ $tests['Folded block chomping strip with multiple trailing newlines'] = array($expected, $yaml);
275
+
276
+ $yaml = <<<'EOF'
277
+ foo: >-
278
+ one
279
+ two
280
+ bar: >-
281
+ one
282
+ two
283
+ EOF;
284
+ $expected = array(
285
+ 'foo' => "one two",
286
+ 'bar' => "one two",
287
+ );
288
+ $tests['Folded block chomping strip without trailing newline'] = array($expected, $yaml);
289
+
290
+ $yaml = <<<'EOF'
291
+ foo: >
292
+ one
293
+ two
294
+ bar: >
295
+ one
296
+ two
297
+
298
+ EOF;
299
+ $expected = array(
300
+ 'foo' => "one two\n",
301
+ 'bar' => "one two\n",
302
+ );
303
+ $tests['Folded block chomping clip with single trailing newline'] = array($expected, $yaml);
304
+
305
+ $yaml = <<<'EOF'
306
+ foo: >
307
+ one
308
+ two
309
+
310
+ bar: >
311
+ one
312
+ two
313
+
314
+
315
+ EOF;
316
+ $expected = array(
317
+ 'foo' => "one two\n",
318
+ 'bar' => "one two\n",
319
+ );
320
+ $tests['Folded block chomping clip with multiple trailing newlines'] = array($expected, $yaml);
321
+
322
+ $yaml = <<<'EOF'
323
+ foo: >
324
+ one
325
+ two
326
+ bar: >
327
+ one
328
+ two
329
+ EOF;
330
+ $expected = array(
331
+ 'foo' => "one two\n",
332
+ 'bar' => "one two",
333
+ );
334
+ $tests['Folded block chomping clip without trailing newline'] = array($expected, $yaml);
335
+
336
+ $yaml = <<<'EOF'
337
+ foo: >+
338
+ one
339
+ two
340
+ bar: >+
341
+ one
342
+ two
343
+
344
+ EOF;
345
+ $expected = array(
346
+ 'foo' => "one two\n",
347
+ 'bar' => "one two\n",
348
+ );
349
+ $tests['Folded block chomping keep with single trailing newline'] = array($expected, $yaml);
350
+
351
+ $yaml = <<<'EOF'
352
+ foo: >+
353
+ one
354
+ two
355
+
356
+ bar: >+
357
+ one
358
+ two
359
+
360
+
361
+ EOF;
362
+ $expected = array(
363
+ 'foo' => "one two\n\n",
364
+ 'bar' => "one two\n\n",
365
+ );
366
+ $tests['Folded block chomping keep with multiple trailing newlines'] = array($expected, $yaml);
367
+
368
+ $yaml = <<<'EOF'
369
+ foo: >+
370
+ one
371
+ two
372
+ bar: >+
373
+ one
374
+ two
375
+ EOF;
376
+ $expected = array(
377
+ 'foo' => "one two\n",
378
+ 'bar' => "one two",
379
+ );
380
+ $tests['Folded block chomping keep without trailing newline'] = array($expected, $yaml);
381
+
382
+ return $tests;
383
+ }
384
+
385
+ /**
386
+ * @dataProvider getBlockChompingTests
387
+ */
388
+ public function testBlockChomping($expected, $yaml)
389
+ {
390
+ $this->assertSame($expected, $this->parser->parse($yaml));
391
+ }
392
+
393
+ /**
394
+ * Regression test for issue #7989.
395
+ *
396
+ * @see https://github.com/symfony/symfony/issues/7989
397
+ */
398
+ public function testBlockLiteralWithLeadingNewlines()
399
+ {
400
+ $yaml = <<<'EOF'
401
+ foo: |-
402
+
403
+
404
+ bar
405
+
406
+ EOF;
407
+ $expected = array(
408
+ 'foo' => "\n\nbar"
409
+ );
410
+
411
+ $this->assertSame($expected, $this->parser->parse($yaml));
412
+ }
413
+
414
+ public function testObjectSupportEnabled()
415
+ {
416
+ $input = <<<EOF
417
+ foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
418
+ bar: 1
419
+ EOF;
420
+ $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects');
421
+ }
422
+
423
+ public function testObjectSupportDisabledButNoExceptions()
424
+ {
425
+ $input = <<<EOF
426
+ foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";}
427
+ bar: 1
428
+ EOF;
429
+
430
+ $this->assertEquals(array('foo' => null, 'bar' => 1), $this->parser->parse($input), '->parse() does not parse objects');
431
+ }
432
+
433
+ /**
434
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
435
+ */
436
+ public function testObjectsSupportDisabledWithExceptions()
437
+ {
438
+ $this->parser->parse('foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";}', true, false);
439
+ }
440
+
441
+ public function testNonUtf8Exception()
442
+ {
443
+ if (!function_exists('iconv')) {
444
+ $this->markTestSkipped('Exceptions for non-utf8 charsets require the iconv() function.');
445
+
446
+ return;
447
+ }
448
+
449
+ $yamls = array(
450
+ iconv("UTF-8", "ISO-8859-1", "foo: 'äöüß'"),
451
+ iconv("UTF-8", "ISO-8859-15", "euro: '€'"),
452
+ iconv("UTF-8", "CP1252", "cp1252: '©ÉÇáñ'")
453
+ );
454
+
455
+ foreach ($yamls as $yaml) {
456
+ try {
457
+ $this->parser->parse($yaml);
458
+
459
+ $this->fail('charsets other than UTF-8 are rejected.');
460
+ } catch (\Exception $e) {
461
+ $this->assertInstanceOf('Symfony\Component\Yaml\Exception\ParseException', $e, 'charsets other than UTF-8 are rejected.');
462
+ }
463
+ }
464
+ }
465
+
466
+ /**
467
+ *
468
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
469
+ *
470
+ */
471
+ public function testUnindentedCollectionException()
472
+ {
473
+ $yaml = <<<EOF
474
+
475
+ collection:
476
+ -item1
477
+ -item2
478
+ -item3
479
+
480
+ EOF;
481
+
482
+ $this->parser->parse($yaml);
483
+ }
484
+
485
+ /**
486
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
487
+ */
488
+ public function testSequenceInAMapping()
489
+ {
490
+ Yaml::parse(<<<EOF
491
+ yaml:
492
+ hash: me
493
+ - array stuff
494
+ EOF
495
+ );
496
+ }
497
+
498
+ /**
499
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
500
+ */
501
+ public function testMappingInASequence()
502
+ {
503
+ Yaml::parse(<<<EOF
504
+ yaml:
505
+ - array stuff
506
+ hash: me
507
+ EOF
508
+ );
509
+ }
510
+
511
+ /**
512
+ * > It is an error for two equal keys to appear in the same mapping node.
513
+ * > In such a case the YAML processor may continue, ignoring the second
514
+ * > `key: value` pair and issuing an appropriate warning. This strategy
515
+ * > preserves a consistent information model for one-pass and random access
516
+ * > applications.
517
+ *
518
+ * @see http://yaml.org/spec/1.2/spec.html#id2759572
519
+ * @see http://yaml.org/spec/1.1/#id932806
520
+ *
521
+ * @covers \Symfony\Component\Yaml\Parser::parse
522
+ */
523
+ public function testMappingDuplicateKeyBlock()
524
+ {
525
+ $input = <<<EOD
526
+ parent:
527
+ child: first
528
+ child: duplicate
529
+ parent:
530
+ child: duplicate
531
+ child: duplicate
532
+ EOD;
533
+ $expected = array(
534
+ 'parent' => array(
535
+ 'child' => 'first',
536
+ ),
537
+ );
538
+ $this->assertSame($expected, Yaml::parse($input));
539
+ }
540
+
541
+ /**
542
+ * @covers \Symfony\Component\Yaml\Inline::parseMapping
543
+ */
544
+ public function testMappingDuplicateKeyFlow()
545
+ {
546
+ $input = <<<EOD
547
+ parent: { child: first, child: duplicate }
548
+ parent: { child: duplicate, child: duplicate }
549
+ EOD;
550
+ $expected = array(
551
+ 'parent' => array(
552
+ 'child' => 'first',
553
+ ),
554
+ );
555
+ $this->assertSame($expected, Yaml::parse($input));
556
+ }
557
+
558
+ public function testEmptyValue()
559
+ {
560
+ $input = <<<EOF
561
+ hash:
562
+ EOF;
563
+
564
+ $this->assertEquals(array('hash' => null), Yaml::parse($input));
565
+ }
566
+
567
+ public function testStringBlockWithComments()
568
+ {
569
+ $this->assertEquals(array('content' => <<<EOT
570
+ # comment 1
571
+ header
572
+
573
+ # comment 2
574
+ <body>
575
+ <h1>title</h1>
576
+ </body>
577
+
578
+ footer # comment3
579
+ EOT
580
+ ), Yaml::parse(<<<EOF
581
+ content: |
582
+ # comment 1
583
+ header
584
+
585
+ # comment 2
586
+ <body>
587
+ <h1>title</h1>
588
+ </body>
589
+
590
+ footer # comment3
591
+ EOF
592
+ ));
593
+ }
594
+
595
+ public function testFoldedStringBlockWithComments()
596
+ {
597
+ $this->assertEquals(array(array('content' => <<<EOT
598
+ # comment 1
599
+ header
600
+
601
+ # comment 2
602
+ <body>
603
+ <h1>title</h1>
604
+ </body>
605
+
606
+ footer # comment3
607
+ EOT
608
+ )), Yaml::parse(<<<EOF
609
+ -
610
+ content: |
611
+ # comment 1
612
+ header
613
+
614
+ # comment 2
615
+ <body>
616
+ <h1>title</h1>
617
+ </body>
618
+
619
+ footer # comment3
620
+ EOF
621
+ ));
622
+ }
623
+
624
+ public function testNestedFoldedStringBlockWithComments()
625
+ {
626
+ $this->assertEquals(array(array(
627
+ 'title' => 'some title',
628
+ 'content' => <<<EOT
629
+ # comment 1
630
+ header
631
+
632
+ # comment 2
633
+ <body>
634
+ <h1>title</h1>
635
+ </body>
636
+
637
+ footer # comment3
638
+ EOT
639
+ )), Yaml::parse(<<<EOF
640
+ -
641
+ title: some title
642
+ content: |
643
+ # comment 1
644
+ header
645
+
646
+ # comment 2
647
+ <body>
648
+ <h1>title</h1>
649
+ </body>
650
+
651
+ footer # comment3
652
+ EOF
653
+ ));
654
+ }
655
+ }
656
+
657
+ class B
658
+ {
659
+ public $b = 'foo';
660
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Tests/YamlTest.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml\Tests;
13
+
14
+ use Symfony\Component\Yaml\Yaml;
15
+
16
+ class YamlTest extends \PHPUnit_Framework_TestCase
17
+ {
18
+ public function testParseAndDump()
19
+ {
20
+ $data = array('lorem' => 'ipsum', 'dolor' => 'sit');
21
+ $yml = Yaml::dump($data);
22
+ $parsed = Yaml::parse($yml);
23
+ $this->assertEquals($data, $parsed);
24
+
25
+ $filename = __DIR__.'/Fixtures/index.yml';
26
+ $contents = file_get_contents($filename);
27
+ $parsedByFilename = Yaml::parse($filename);
28
+ $parsedByContents = Yaml::parse($contents);
29
+ $this->assertEquals($parsedByFilename, $parsedByContents);
30
+ }
31
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Unescaper.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml;
13
+
14
+ /**
15
+ * Unescaper encapsulates unescaping rules for single and double-quoted
16
+ * YAML strings.
17
+ *
18
+ * @author Matthew Lewinski <matthew@lewinski.org>
19
+ */
20
+ class Unescaper
21
+ {
22
+ // Parser and Inline assume UTF-8 encoding, so escaped Unicode characters
23
+ // must be converted to that encoding.
24
+ // @deprecated since 2.5, to be removed in 3.0
25
+ const ENCODING = 'UTF-8';
26
+
27
+ // Regex fragment that matches an escaped character in a double quoted
28
+ // string.
29
+ const REGEX_ESCAPED_CHARACTER = "\\\\([0abt\tnvfre \\\"\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})";
30
+
31
+ /**
32
+ * Unescapes a single quoted string.
33
+ *
34
+ * @param string $value A single quoted string.
35
+ *
36
+ * @return string The unescaped string.
37
+ */
38
+ public function unescapeSingleQuotedString($value)
39
+ {
40
+ return str_replace('\'\'', '\'', $value);
41
+ }
42
+
43
+ /**
44
+ * Unescapes a double quoted string.
45
+ *
46
+ * @param string $value A double quoted string.
47
+ *
48
+ * @return string The unescaped string.
49
+ */
50
+ public function unescapeDoubleQuotedString($value)
51
+ {
52
+ $self = $this;
53
+ $callback = function ($match) use ($self) {
54
+ return $self->unescapeCharacter($match[0]);
55
+ };
56
+
57
+ // evaluate the string
58
+ return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
59
+ }
60
+
61
+ /**
62
+ * Unescapes a character that was found in a double-quoted string
63
+ *
64
+ * @param string $value An escaped character
65
+ *
66
+ * @return string The unescaped character
67
+ */
68
+ public function unescapeCharacter($value)
69
+ {
70
+ switch ($value{1}) {
71
+ case '0':
72
+ return "\x0";
73
+ case 'a':
74
+ return "\x7";
75
+ case 'b':
76
+ return "\x8";
77
+ case 't':
78
+ return "\t";
79
+ case "\t":
80
+ return "\t";
81
+ case 'n':
82
+ return "\n";
83
+ case 'v':
84
+ return "\xB";
85
+ case 'f':
86
+ return "\xC";
87
+ case 'r':
88
+ return "\r";
89
+ case 'e':
90
+ return "\x1B";
91
+ case ' ':
92
+ return ' ';
93
+ case '"':
94
+ return '"';
95
+ case '/':
96
+ return '/';
97
+ case '\\':
98
+ return '\\';
99
+ case 'N':
100
+ // U+0085 NEXT LINE
101
+ return "\xC2\x85";
102
+ case '_':
103
+ // U+00A0 NO-BREAK SPACE
104
+ return "\xC2\xA0";
105
+ case 'L':
106
+ // U+2028 LINE SEPARATOR
107
+ return "\xE2\x80\xA8";
108
+ case 'P':
109
+ // U+2029 PARAGRAPH SEPARATOR
110
+ return "\xE2\x80\xA9";
111
+ case 'x':
112
+ return self::utf8chr(hexdec(substr($value, 2, 2)));
113
+ case 'u':
114
+ return self::utf8chr(hexdec(substr($value, 2, 4)));
115
+ case 'U':
116
+ return self::utf8chr(hexdec(substr($value, 2, 8)));
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Get the UTF-8 character for the given code point.
122
+ *
123
+ * @param int $c The unicode code point
124
+ *
125
+ * @return string The corresponding UTF-8 character
126
+ */
127
+ private static function utf8chr($c)
128
+ {
129
+ if (0x80 > $c %= 0x200000) {
130
+ return chr($c);
131
+ }
132
+ if (0x800 > $c) {
133
+ return chr(0xC0 | $c>>6).chr(0x80 | $c & 0x3F);
134
+ }
135
+ if (0x10000 > $c) {
136
+ return chr(0xE0 | $c>>12).chr(0x80 | $c>>6 & 0x3F).chr(0x80 | $c & 0x3F);
137
+ }
138
+
139
+ return chr(0xF0 | $c>>18).chr(0x80 | $c>>12 & 0x3F).chr(0x80 | $c>>6 & 0x3F).chr(0x80 | $c & 0x3F);
140
+ }
141
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/Yaml.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of the Symfony package.
5
+ *
6
+ * (c) Fabien Potencier <fabien@symfony.com>
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
+ namespace Symfony\Component\Yaml;
13
+
14
+ use Symfony\Component\Yaml\Exception\ParseException;
15
+
16
+ /**
17
+ * Yaml offers convenience methods to load and dump YAML.
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ *
21
+ * @api
22
+ */
23
+ class Yaml
24
+ {
25
+ /**
26
+ * Parses YAML into a PHP array.
27
+ *
28
+ * The parse method, when supplied with a YAML stream (string or file),
29
+ * will do its best to convert YAML in a file into a PHP array.
30
+ *
31
+ * Usage:
32
+ * <code>
33
+ * $array = Yaml::parse('config.yml');
34
+ * print_r($array);
35
+ * </code>
36
+ *
37
+ * As this method accepts both plain strings and file names as an input,
38
+ * you must validate the input before calling this method. Passing a file
39
+ * as an input is a deprecated feature and will be removed in 3.0.
40
+ *
41
+ * @param string $input Path to a YAML file or a string containing YAML
42
+ * @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise
43
+ * @param bool $objectSupport True if object support is enabled, false otherwise
44
+ *
45
+ * @return array The YAML converted to a PHP array
46
+ *
47
+ * @throws ParseException If the YAML is not valid
48
+ *
49
+ * @api
50
+ */
51
+ public static function parse($input, $exceptionOnInvalidType = false, $objectSupport = false)
52
+ {
53
+ // if input is a file, process it
54
+ $file = '';
55
+ if (strpos($input, "\n") === false && is_file($input)) {
56
+ if (false === is_readable($input)) {
57
+ throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $input));
58
+ }
59
+
60
+ $file = $input;
61
+ $input = file_get_contents($file);
62
+ }
63
+
64
+ $yaml = new Parser();
65
+
66
+ try {
67
+ return $yaml->parse($input, $exceptionOnInvalidType, $objectSupport);
68
+ } catch (ParseException $e) {
69
+ if ($file) {
70
+ $e->setParsedFile($file);
71
+ }
72
+
73
+ throw $e;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Dumps a PHP array to a YAML string.
79
+ *
80
+ * The dump method, when supplied with an array, will do its best
81
+ * to convert the array into friendly YAML.
82
+ *
83
+ * @param array $array PHP array
84
+ * @param int $inline The level where you switch to inline YAML
85
+ * @param int $indent The amount of spaces to use for indentation of nested nodes.
86
+ * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
87
+ * @param bool $objectSupport true if object support is enabled, false otherwise
88
+ *
89
+ * @return string A YAML string representing the original PHP array
90
+ *
91
+ * @api
92
+ */
93
+ public static function dump($array, $inline = 2, $indent = 4, $exceptionOnInvalidType = false, $objectSupport = false)
94
+ {
95
+ $yaml = new Dumper();
96
+ $yaml->setIndentation($indent);
97
+
98
+ return $yaml->dump($array, $inline, 0, $exceptionOnInvalidType, $objectSupport);
99
+ }
100
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/composer.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "symfony/yaml",
3
+ "type": "library",
4
+ "description": "Symfony Yaml Component",
5
+ "keywords": [],
6
+ "homepage": "http://symfony.com",
7
+ "license": "MIT",
8
+ "authors": [
9
+ {
10
+ "name": "Fabien Potencier",
11
+ "email": "fabien@symfony.com"
12
+ },
13
+ {
14
+ "name": "Symfony Community",
15
+ "homepage": "http://symfony.com/contributors"
16
+ }
17
+ ],
18
+ "require": {
19
+ "php": ">=5.3.3"
20
+ },
21
+ "autoload": {
22
+ "psr-0": { "Symfony\\Component\\Yaml\\": "" }
23
+ },
24
+ "target-dir": "Symfony/Component/Yaml",
25
+ "minimum-stability": "dev",
26
+ "extra": {
27
+ "branch-alias": {
28
+ "dev-master": "2.5-dev"
29
+ }
30
+ }
31
+ }
vendor/vendor/symfony/yaml/Symfony/Component/Yaml/phpunit.xml.dist ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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="Symfony Yaml Component Test Suite">
16
+ <directory>./Tests/</directory>
17
+ </testsuite>
18
+ </testsuites>
19
+
20
+ <filter>
21
+ <whitelist>
22
+ <directory>./</directory>
23
+ <exclude>
24
+ <directory>./vendor</directory>
25
+ <directory>./Tests</directory>
26
+ </exclude>
27
+ </whitelist>
28
+ </filter>
29
+ </phpunit>
vendor/vendor/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
vendor/vendor/twig/twig/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /ext/twig/autom4te.cache/
2
+
vendor/vendor/twig/twig/.travis.yml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.2
5
+ - 5.3
6
+ - 5.4
7
+ - 5.5
8
+ - hhvm
9
+
10
+ env:
11
+ - TWIG_EXT=no
12
+ - TWIG_EXT=yes
13
+
14
+ before_script:
15
+ - if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && sudo make install"; fi
16
+ - if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi
17
+
18
+ matrix:
19
+ exclude:
20
+ - php: hhvm
21
+ env: TWIG_EXT=yes
vendor/vendor/twig/twig/CHANGELOG ADDED
@@ -0,0 +1,677 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * 1.15.1 (2013-02-13)
2
+
3
+ * fixed the conversion of the special '0000-00-00 00:00' date
4
+ * added an error message when trying to import an undefined block from a trait
5
+ * fixed a C extension crash when accessing defined but uninitialized property.
6
+
7
+ * 1.15.0 (2013-12-06)
8
+
9
+ * made ignoreStrictCheck in Template::getAttribute() works with __call() methods throwing BadMethodCallException
10
+ * added min and max functions
11
+ * added the round filter
12
+ * fixed a bug that prevented the optimizers to be enabled/disabled selectively
13
+ * fixed first and last filters for UTF-8 strings
14
+ * added a source function to include the content of a template without rendering it
15
+ * fixed the C extension sandbox behavior when get or set is prepend to method name
16
+
17
+ * 1.14.2 (2013-10-30)
18
+
19
+ * fixed error filename/line when an error occurs in an included file
20
+ * allowed operators that contain whitespaces to have more than one whitespace
21
+ * allowed tests to be made of 1 or 2 words (like "same as" or "divisible by")
22
+
23
+ * 1.14.1 (2013-10-15)
24
+
25
+ * made it possible to use named operators as variables
26
+ * fixed the possibility to have a variable named 'matches'
27
+ * added support for PHP 5.5 DateTimeInterface
28
+
29
+ * 1.14.0 (2013-10-03)
30
+
31
+ * fixed usage of the html_attr escaping strategy to avoid double-escaping with the html strategy
32
+ * added new operators: ends with, starts with, and matches
33
+ * fixed some compatibility issues with HHVM
34
+ * added a way to add custom escaping strategies
35
+ * fixed the C extension compilation on Windows
36
+ * fixed the batch filter when using a fill argument with an exact match of elements to batch
37
+ * fixed the filesystem loader cache when a template name exists in several namespaces
38
+ * fixed template_from_string when the template includes or extends other ones
39
+ * fixed a crash of the C extension on an edge case
40
+
41
+ * 1.13.2 (2013-08-03)
42
+
43
+ * fixed the error line number for an error occurs in and embedded template
44
+ * fixed crashes of the C extension on some edge cases
45
+
46
+ * 1.13.1 (2013-06-06)
47
+
48
+ * added the possibility to ignore the filesystem constructor argument in Twig_Loader_Filesystem
49
+ * fixed Twig_Loader_Chain::exists() for a loader which implements Twig_ExistsLoaderInterface
50
+ * adjusted backtrace call to reduce memory usage when an error occurs
51
+ * added support for object instances as the second argument of the constant test
52
+ * fixed the include function when used in an assignment
53
+
54
+ * 1.13.0 (2013-05-10)
55
+
56
+ * fixed getting a numeric-like item on a variable ('09' for instance)
57
+ * fixed getting a boolean or float key on an array, so it is consistent with PHP's array access:
58
+ `{{ array[false] }}` behaves the same as `echo $array[false];` (equals `$array[0]`)
59
+ * made the escape filter 20% faster for happy path (escaping string for html with UTF-8)
60
+ * changed ☃ to § in tests
61
+ * enforced usage of named arguments after positional ones
62
+
63
+ * 1.12.3 (2013-04-08)
64
+
65
+ * fixed a security issue in the filesystem loader where it was possible to include a template one
66
+ level above the configured path
67
+ * fixed fatal error that should be an exception when adding a filter/function/test too late
68
+ * added a batch filter
69
+ * added support for encoding an array as query string in the url_encode filter
70
+
71
+ * 1.12.2 (2013-02-09)
72
+
73
+ * fixed the timezone used by the date filter and function when the given date contains a timezone (like 2010-01-28T15:00:00+02:00)
74
+ * fixed globals when getGlobals is called early on
75
+ * added the first and last filter
76
+
77
+ * 1.12.1 (2013-01-15)
78
+
79
+ * added support for object instances as the second argument of the constant function
80
+ * relaxed globals management to avoid a BC break
81
+ * added support for {{ some_string[:2] }}
82
+
83
+ * 1.12.0 (2013-01-08)
84
+
85
+ * added verbatim as an alias for the raw tag to avoid confusion with the raw filter
86
+ * fixed registration of tests and functions as anonymous functions
87
+ * fixed globals management
88
+
89
+ * 1.12.0-RC1 (2012-12-29)
90
+
91
+ * added an include function (does the same as the include tag but in a more flexible way)
92
+ * added the ability to use any PHP callable to define filters, functions, and tests
93
+ * added a syntax error when using a loop variable that is not defined
94
+ * added the ability to set default values for macro arguments
95
+ * added support for named arguments for filters, tests, and functions
96
+ * moved filters/functions/tests syntax errors to the parser
97
+ * added support for extended ternary operator syntaxes
98
+
99
+ * 1.11.1 (2012-11-11)
100
+
101
+ * fixed debug info line numbering (was off by 2)
102
+ * fixed escaping when calling a macro inside another one (regression introduced in 1.9.1)
103
+ * optimized variable access on PHP 5.4
104
+ * fixed a crash of the C extension when an exception was thrown from a macro called without being imported (using _self.XXX)
105
+
106
+ * 1.11.0 (2012-11-07)
107
+
108
+ * fixed macro compilation when a variable name is a PHP reserved keyword
109
+ * changed the date filter behavior to always apply the default timezone, except if false is passed as the timezone
110
+ * fixed bitwise operator precedences
111
+ * added the template_from_string function
112
+ * fixed default timezone usage for the date function
113
+ * optimized the way Twig exceptions are managed (to make them faster)
114
+ * added Twig_ExistsLoaderInterface (implementing this interface in your loader make the chain loader much faster)
115
+
116
+ * 1.10.3 (2012-10-19)
117
+
118
+ * fixed wrong template location in some error messages
119
+ * reverted a BC break introduced in 1.10.2
120
+ * added a split filter
121
+
122
+ * 1.10.2 (2012-10-15)
123
+
124
+ * fixed macro calls on PHP 5.4
125
+
126
+ * 1.10.1 (2012-10-15)
127
+
128
+ * made a speed optimization to macro calls when imported via the "import" tag
129
+ * fixed C extension compilation on Windows
130
+ * fixed a segfault in the C extension when using DateTime objects
131
+
132
+ * 1.10.0 (2012-09-28)
133
+
134
+ * extracted functional tests framework to make it reusable for third-party extensions
135
+ * added namespaced templates support in Twig_Loader_Filesystem
136
+ * added Twig_Loader_Filesystem::prependPath()
137
+ * fixed an error when a token parser pass a closure as a test to the subparse() method
138
+
139
+ * 1.9.2 (2012-08-25)
140
+
141
+ * fixed the in operator for objects that contain circular references
142
+ * fixed the C extension when accessing a public property of an object implementing the \ArrayAccess interface
143
+
144
+ * 1.9.1 (2012-07-22)
145
+
146
+ * optimized macro calls when auto-escaping is on
147
+ * fixed wrong parent class for Twig_Function_Node
148
+ * made Twig_Loader_Chain more explicit about problems
149
+
150
+ * 1.9.0 (2012-07-13)
151
+
152
+ * made the parsing independent of the template loaders
153
+ * fixed exception trace when an error occurs when rendering a child template
154
+ * added escaping strategies for CSS, URL, and HTML attributes
155
+ * fixed nested embed tag calls
156
+ * added the date_modify filter
157
+
158
+ * 1.8.3 (2012-06-17)
159
+
160
+ * fixed paths in the filesystem loader when passing a path that ends with a slash or a backslash
161
+ * fixed escaping when a project defines a function named html or js
162
+ * fixed chmod mode to apply the umask correctly
163
+
164
+ * 1.8.2 (2012-05-30)
165
+
166
+ * added the abs filter
167
+ * fixed a regression when using a number in template attributes
168
+ * fixed compiler when mbstring.func_overload is set to 2
169
+ * fixed DateTimeZone support in date filter
170
+
171
+ * 1.8.1 (2012-05-17)
172
+
173
+ * fixed a regression when dealing with SimpleXMLElement instances in templates
174
+ * fixed "is_safe" value for the "dump" function when "html_errors" is not defined in php.ini
175
+ * switched to use mbstring whenever possible instead of iconv (you might need to update your encoding as mbstring and iconv encoding names sometimes differ)
176
+
177
+ * 1.8.0 (2012-05-08)
178
+
179
+ * enforced interface when adding tests, filters, functions, and node visitors from extensions
180
+ * fixed a side-effect of the date filter where the timezone might be changed
181
+ * simplified usage of the autoescape tag; the only (optional) argument is now the escaping strategy or false (with a BC layer)
182
+ * added a way to dynamically change the auto-escaping strategy according to the template "filename"
183
+ * changed the autoescape option to also accept a supported escaping strategy (for BC, true is equivalent to html)
184
+ * added an embed tag
185
+
186
+ * 1.7.0 (2012-04-24)
187
+
188
+ * fixed a PHP warning when using CIFS
189
+ * fixed template line number in some exceptions
190
+ * added an iterable test
191
+ * added an error when defining two blocks with the same name in a template
192
+ * added the preserves_safety option for filters
193
+ * fixed a PHP notice when trying to access a key on a non-object/array variable
194
+ * enhanced error reporting when the template file is an instance of SplFileInfo
195
+ * added Twig_Environment::mergeGlobals()
196
+ * added compilation checks to avoid misuses of the sandbox tag
197
+ * fixed filesystem loader freshness logic for high traffic websites
198
+ * fixed random function when charset is null
199
+
200
+ * 1.6.5 (2012-04-11)
201
+
202
+ * fixed a regression when a template only extends another one without defining any blocks
203
+
204
+ * 1.6.4 (2012-04-02)
205
+
206
+ * fixed PHP notice in Twig_Error::guessTemplateLine() introduced in 1.6.3
207
+ * fixed performance when compiling large files
208
+ * optimized parent template creation when the template does not use dynamic inheritance
209
+
210
+ * 1.6.3 (2012-03-22)
211
+
212
+ * fixed usage of Z_ADDREF_P for PHP 5.2 in the C extension
213
+ * fixed compilation of numeric values used in templates when using a locale where the decimal separator is not a dot
214
+ * made the strategy used to guess the real template file name and line number in exception messages much faster and more accurate
215
+
216
+ * 1.6.2 (2012-03-18)
217
+
218
+ * fixed sandbox mode when used with inheritance
219
+ * added preserveKeys support for the slice filter
220
+ * fixed the date filter when a DateTime instance is passed with a specific timezone
221
+ * added a trim filter
222
+
223
+ * 1.6.1 (2012-02-29)
224
+
225
+ * fixed Twig C extension
226
+ * removed the creation of Twig_Markup instances when not needed
227
+ * added a way to set the default global timezone for dates
228
+ * fixed the slice filter on strings when the length is not specified
229
+ * fixed the creation of the cache directory in case of a race condition
230
+
231
+ * 1.6.0 (2012-02-04)
232
+
233
+ * fixed raw blocks when used with the whitespace trim option
234
+ * made a speed optimization to macro calls when imported via the "from" tag
235
+ * fixed globals, parsers, visitors, filters, tests, and functions management in Twig_Environment when a new one or new extension is added
236
+ * fixed the attribute function when passing arguments
237
+ * added slice notation support for the [] operator (syntactic sugar for the slice operator)
238
+ * added a slice filter
239
+ * added string support for the reverse filter
240
+ * fixed the empty test and the length filter for Twig_Markup instances
241
+ * added a date function to ease date comparison
242
+ * fixed unary operators precedence
243
+ * added recursive parsing support in the parser
244
+ * added string and integer handling for the random function
245
+
246
+ * 1.5.1 (2012-01-05)
247
+
248
+ * fixed a regression when parsing strings
249
+
250
+ * 1.5.0 (2012-01-04)
251
+
252
+ * added Traversable objects support for the join filter
253
+
254
+ * 1.5.0-RC2 (2011-12-30)
255
+
256
+ * added a way to set the default global date interval format
257
+ * fixed the date filter for DateInterval instances (setTimezone() does not exist for them)
258
+ * refactored Twig_Template::display() to ease its extension
259
+ * added a number_format filter
260
+
261
+ * 1.5.0-RC1 (2011-12-26)
262
+
263
+ * removed the need to quote hash keys
264
+ * allowed hash keys to be any expression
265
+ * added a do tag
266
+ * added a flush tag
267
+ * added support for dynamically named filters and functions
268
+ * added a dump function to help debugging templates
269
+ * added a nl2br filter
270
+ * added a random function
271
+ * added a way to change the default format for the date filter
272
+ * fixed the lexer when an operator ending with a letter ends a line
273
+ * added string interpolation support
274
+ * enhanced exceptions for unknown filters, functions, tests, and tags
275
+
276
+ * 1.4.0 (2011-12-07)
277
+
278
+ * fixed lexer when using big numbers (> PHP_INT_MAX)
279
+ * added missing preserveKeys argument to the reverse filter
280
+ * fixed macros containing filter tag calls
281
+
282
+ * 1.4.0-RC2 (2011-11-27)
283
+
284
+ * removed usage of Reflection in Twig_Template::getAttribute()
285
+ * added a C extension that can optionally replace Twig_Template::getAttribute()
286
+ * added negative timestamp support to the date filter
287
+
288
+ * 1.4.0-RC1 (2011-11-20)
289
+
290
+ * optimized variable access when using PHP 5.4
291
+ * changed the precedence of the .. operator to be more consistent with languages that implements such a feature like Ruby
292
+ * added an Exception to Twig_Loader_Array::isFresh() method when the template does not exist to be consistent with other loaders
293
+ * added Twig_Function_Node to allow more complex functions to have their own Node class
294
+ * added Twig_Filter_Node to allow more complex filters to have their own Node class
295
+ * added Twig_Test_Node to allow more complex tests to have their own Node class
296
+ * added a better error message when a template is empty but contain a BOM
297
+ * fixed "in" operator for empty strings
298
+ * fixed the "defined" test and the "default" filter (now works with more than one call (foo.bar.foo) and for both values of the strict_variables option)
299
+ * changed the way extensions are loaded (addFilter/addFunction/addGlobal/addTest/addNodeVisitor/addTokenParser/addExtension can now be called in any order)
300
+ * added Twig_Environment::display()
301
+ * made the escape filter smarter when the encoding is not supported by PHP
302
+ * added a convert_encoding filter
303
+ * moved all node manipulations outside the compile() Node method
304
+ * made several speed optimizations
305
+
306
+ * 1.3.0 (2011-10-08)
307
+
308
+ no changes
309
+
310
+ * 1.3.0-RC1 (2011-10-04)
311
+
312
+ * added an optimization for the parent() function
313
+ * added cache reloading when auto_reload is true and an extension has been modified
314
+ * added the possibility to force the escaping of a string already marked as safe (instance of Twig_Markup)
315
+ * allowed empty templates to be used as traits
316
+ * added traits support for the "parent" function
317
+
318
+ * 1.2.0 (2011-09-13)
319
+
320
+ no changes
321
+
322
+ * 1.2.0-RC1 (2011-09-10)
323
+
324
+ * enhanced the exception when a tag remains unclosed
325
+ * added support for empty Countable objects for the "empty" test
326
+ * fixed algorithm that determines if a template using inheritance is valid (no output between block definitions)
327
+ * added better support for encoding problems when escaping a string (available as of PHP 5.4)
328
+ * added a way to ignore a missing template when using the "include" tag ({% include "foo" ignore missing %})
329
+ * added support for an array of templates to the "include" and "extends" tags ({% include ['foo', 'bar'] %})
330
+ * added support for bitwise operators in expressions
331
+ * added the "attribute" function to allow getting dynamic attributes on variables
332
+ * added Twig_Loader_Chain
333
+ * added Twig_Loader_Array::setTemplate()
334
+ * added an optimization for the set tag when used to capture a large chunk of static text
335
+ * changed name regex to match PHP one "[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*" (works for blocks, tags, functions, filters, and macros)
336
+ * removed the possibility to use the "extends" tag from a block
337
+ * added "if" modifier support to "for" loops
338
+
339
+ * 1.1.2 (2011-07-30)
340
+
341
+ * fixed json_encode filter on PHP 5.2
342
+ * fixed regression introduced in 1.1.1 ({{ block(foo|lower) }})
343
+ * fixed inheritance when using conditional parents
344
+ * fixed compilation of templates when the body of a child template is not empty
345
+ * fixed output when a macro throws an exception
346
+ * fixed a parsing problem when a large chunk of text is enclosed in a comment tag
347
+ * added PHPDoc for all Token parsers and Core extension functions
348
+
349
+ * 1.1.1 (2011-07-17)
350
+
351
+ * added a performance optimization in the Optimizer (also helps to lower the number of nested level calls)
352
+ * made some performance improvement for some edge cases
353
+
354
+ * 1.1.0 (2011-06-28)
355
+
356
+ * fixed json_encode filter
357
+
358
+ * 1.1.0-RC3 (2011-06-24)
359
+
360
+ * fixed method case-sensitivity when using the sandbox mode
361
+ * added timezone support for the date filter
362
+ * fixed possible security problems with NUL bytes
363
+
364
+ * 1.1.0-RC2 (2011-06-16)
365
+
366
+ * added an exception when the template passed to "use" is not a string
367
+ * made 'a.b is defined' not throw an exception if a is not defined (in strict mode)
368
+ * added {% line \d+ %} directive
369
+
370
+ * 1.1.0-RC1 (2011-05-28)
371
+
372
+ Flush your cache after upgrading.
373
+
374
+ * fixed date filter when using a timestamp
375
+ * fixed the defined test for some cases
376
+ * fixed a parsing problem when a large chunk of text is enclosed in a raw tag
377
+ * added support for horizontal reuse of template blocks (see docs for more information)
378
+ * added whitespace control modifier to all tags (see docs for more information)
379
+ * added null as an alias for none (the null test is also an alias for the none test now)
380
+ * made TRUE, FALSE, NONE equivalent to their lowercase counterparts
381
+ * wrapped all compilation and runtime exceptions with Twig_Error_Runtime and added logic to guess the template name and line
382
+ * moved display() method to Twig_Template (generated templates should now use doDisplay() instead)
383
+
384
+ * 1.0.0 (2011-03-27)
385
+
386
+ * fixed output when using mbstring
387
+ * fixed duplicate call of methods when using the sandbox
388
+ * made the charset configurable for the escape filter
389
+
390
+ * 1.0.0-RC2 (2011-02-21)
391
+
392
+ * changed the way {% set %} works when capturing (the content is now marked as safe)
393
+ * added support for macro name in the endmacro tag
394
+ * make Twig_Error compatible with PHP 5.3.0 >
395
+ * fixed an infinite loop on some Windows configurations
396
+ * fixed the "length" filter for numbers
397
+ * fixed Template::getAttribute() as properties in PHP are case sensitive
398
+ * removed coupling between Twig_Node and Twig_Template
399
+ * fixed the ternary operator precedence rule
400
+
401
+ * 1.0.0-RC1 (2011-01-09)
402
+
403
+ Backward incompatibilities:
404
+
405
+ * the "items" filter, which has been deprecated for quite a long time now, has been removed
406
+ * the "range" filter has been converted to a function: 0|range(10) -> range(0, 10)
407
+ * the "constant" filter has been converted to a function: {{ some_date|date('DATE_W3C'|constant) }} -> {{ some_date|date(constant('DATE_W3C')) }}
408
+ * the "cycle" filter has been converted to a function: {{ ['odd', 'even']|cycle(i) }} -> {{ cycle(['odd', 'even'], i) }}
409
+ * the "for" tag does not support "joined by" anymore
410
+ * the "autoescape" first argument is now "true"/"false" (instead of "on"/"off")
411
+ * the "parent" tag has been replaced by a "parent" function ({{ parent() }} instead of {% parent %})
412
+ * the "display" tag has been replaced by a "block" function ({{ block('title') }} instead of {% display title %})
413
+ * removed the grammar and simple token parser (moved to the Twig Extensions repository)
414
+
415
+ Changes:
416
+
417
+ * added "needs_context" option for filters and functions (the context is then passed as a first argument)
418
+ * added global variables support
419
+ * made macros return their value instead of echoing directly (fixes calling a macro in sandbox mode)
420
+ * added the "from" tag to import macros as functions
421
+ * added support for functions (a function is just syntactic sugar for a getAttribute() call)
422
+ * made macros callable when sandbox mode is enabled
423
+ * added an exception when a macro uses a reserved name
424
+ * the "default" filter now uses the "empty" test instead of just checking for null
425
+ * added the "empty" test
426
+
427
+ * 0.9.10 (2010-12-16)
428
+
429
+ Backward incompatibilities:
430
+
431
+ * The Escaper extension is enabled by default, which means that all displayed
432
+ variables are now automatically escaped. You can revert to the previous
433
+ behavior by removing the extension via $env->removeExtension('escaper')
434
+ or just set the 'autoescape' option to 'false'.
435
+ * removed the "without loop" attribute for the "for" tag (not needed anymore
436
+ as the Optimizer take care of that for most cases)
437
+ * arrays and hashes have now a different syntax
438
+ * arrays keep the same syntax with square brackets: [1, 2]
439
+ * hashes now use curly braces (["a": "b"] should now be written as {"a": "b"})
440
+ * support for "arrays with keys" and "hashes without keys" is not supported anymore ([1, "foo": "bar"] or {"foo": "bar", 1})
441
+ * the i18n extension is now part of the Twig Extensions repository
442
+
443
+ Changes:
444
+
445
+ * added the merge filter
446
+ * removed 'is_escaper' option for filters (a left over from the previous version) -- you must use 'is_safe' now instead
447
+ * fixed usage of operators as method names (like is, in, and not)
448
+ * changed the order of execution for node visitors
449
+ * fixed default() filter behavior when used with strict_variables set to on
450
+ * fixed filesystem loader compatibility with PHAR files
451
+ * enhanced error messages when an unexpected token is parsed in an expression
452
+ * fixed filename not being added to syntax error messages
453
+ * added the autoescape option to enable/disable autoescaping
454
+ * removed the newline after a comment (mimics PHP behavior)
455
+ * added a syntax error exception when parent block is used on a template that does not extend another one
456
+ * made the Escaper extension enabled by default
457
+ * fixed sandbox extension when used with auto output escaping
458
+ * fixed escaper when wrapping a Twig_Node_Print (the original class must be preserved)
459
+ * added an Optimizer extension (enabled by default; optimizes "for" loops and "raw" filters)
460
+ * added priority to node visitors
461
+
462
+ * 0.9.9 (2010-11-28)
463
+
464
+ Backward incompatibilities:
465
+ * the self special variable has been renamed to _self
466
+ * the odd and even filters are now tests:
467
+ {{ foo|odd }} must now be written {{ foo is odd }}
468
+ * the "safe" filter has been renamed to "raw"
469
+ * in Node classes,
470
+ sub-nodes are now accessed via getNode() (instead of property access)
471
+ attributes via getAttribute() (instead of array access)
472
+ * the urlencode filter had been renamed to url_encode
473
+ * the include tag now merges the passed variables with the current context by default
474
+ (the old behavior is still possible by adding the "only" keyword)
475
+ * moved Exceptions to Twig_Error_* (Twig_SyntaxError/Twig_RuntimeError are now Twig_Error_Syntax/Twig_Error_Runtime)
476
+ * removed support for {{ 1 < i < 3 }} (use {{ i > 1 and i < 3 }} instead)
477
+ * the "in" filter has been removed ({{ a|in(b) }} should now be written {{ a in b }})
478
+
479
+ Changes:
480
+ * added file and line to Twig_Error_Runtime exceptions thrown from Twig_Template
481
+ * changed trans tag to accept any variable for the plural count
482
+ * fixed sandbox mode (__toString() method check was not enforced if called implicitly from complex statements)
483
+ * added the ** (power) operator
484
+ * changed the algorithm used for parsing expressions
485
+ * added the spaceless tag
486
+ * removed trim_blocks option
487
+ * added support for is*() methods for attributes (foo.bar now looks for foo->getBar() or foo->isBar())
488
+ * changed all exceptions to extend Twig_Error
489
+ * fixed unary expressions ({{ not(1 or 0) }})
490
+ * fixed child templates (with an extend tag) that uses one or more imports
491
+ * added support for {{ 1 not in [2, 3] }} (more readable than the current {{ not (1 in [2, 3]) }})
492
+ * escaping has been rewritten
493
+ * the implementation of template inheritance has been rewritten
494
+ (blocks can now be called individually and still work with inheritance)
495
+ * fixed error handling for if tag when a syntax error occurs within a subparse process
496
+ * added a way to implement custom logic for resolving token parsers given a tag name
497
+ * fixed js escaper to be stricter (now uses a whilelist-based js escaper)
498
+ * added the following filers: "constant", "trans", "replace", "json_encode"
499
+ * added a "constant" test
500
+ * fixed objects with __toString() not being autoescaped
501
+ * fixed subscript expressions when calling __call() (methods now keep the case)
502
+ * added "test" feature (accessible via the "is" operator)
503
+ * removed the debug tag (should be done in an extension)
504
+ * fixed trans tag when no vars are used in plural form
505
+ * fixed race condition when writing template cache
506
+ * added the special _charset variable to reference the current charset
507
+ * added the special _context variable to reference the current context
508
+ * renamed self to _self (to avoid conflict)
509
+ * fixed Twig_Template::getAttribute() for protected properties
510
+
511
+ * 0.9.8 (2010-06-28)
512
+
513
+ Backward incompatibilities:
514
+ * the trans tag plural count is now attached to the plural tag:
515
+ old: `{% trans count %}...{% plural %}...{% endtrans %}`
516
+ new: `{% trans %}...{% plural count %}...{% endtrans %}`
517
+
518
+ * added a way to translate strings coming from a variable ({% trans var %})
519
+ * fixed trans tag when used with the Escaper extension
520
+ * fixed default cache umask
521
+ * removed Twig_Template instances from the debug tag output
522
+ * fixed objects with __isset() defined
523
+ * fixed set tag when used with a capture
524
+ * fixed type hinting for Twig_Environment::addFilter() method
525
+
526
+ * 0.9.7 (2010-06-12)
527
+
528
+ Backward incompatibilities:
529
+ * changed 'as' to '=' for the set tag ({% set title as "Title" %} must now be {% set title = "Title" %})
530
+ * removed the sandboxed attribute of the include tag (use the new sandbox tag instead)
531
+ * refactored the Node system (if you have custom nodes, you will have to update them to use the new API)
532
+
533
+ * added self as a special variable that refers to the current template (useful for importing macros from the current template)
534
+ * added Twig_Template instance support to the include tag
535
+ * added support for dynamic and conditional inheritance ({% extends some_var %} and {% extends standalone ? "minimum" : "base" %})
536
+ * added a grammar sub-framework to ease the creation of custom tags
537
+ * fixed the for tag for large arrays (some loop variables are now only available for arrays and objects that implement the Countable interface)
538
+ * removed the Twig_Resource::resolveMissingFilter() method
539
+ * fixed the filter tag which did not apply filtering to included files
540
+ * added a bunch of unit tests
541
+ * added a bunch of phpdoc
542
+ * added a sandbox tag in the sandbox extension
543
+ * changed the date filter to support any date format supported by DateTime
544
+ * added strict_variable setting to throw an exception when an invalid variable is used in a template (disabled by default)
545
+ * added the lexer, parser, and compiler as arguments to the Twig_Environment constructor
546
+ * changed the cache option to only accepts an explicit path to a cache directory or false
547
+ * added a way to add token parsers, filters, and visitors without creating an extension
548
+ * added three interfaces: Twig_NodeInterface, Twig_TokenParserInterface, and Twig_FilterInterface
549
+ * changed the generated code to match the new coding standards
550
+ * fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }})
551
+ * added an exception when a child template has a non-empty body (as it is always ignored when rendering)
552
+
553
+ * 0.9.6 (2010-05-12)
554
+
555
+ * fixed variables defined outside a loop and for which the value changes in a for loop
556
+ * fixed the test suite for PHP 5.2 and older versions of PHPUnit
557
+ * added support for __call() in expression resolution
558
+ * fixed node visiting for macros (macros are now visited by visitors as any other node)
559
+ * fixed nested block definitions with a parent call (rarely useful but nonetheless supported now)
560
+ * added the cycle filter
561
+ * fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
562
+ * added a long-syntax for the set tag ({% set foo %}...{% endset %})
563
+ * unit tests are now powered by PHPUnit
564
+ * added support for gettext via the `i18n` extension
565
+ * fixed twig_capitalize_string_filter() and fixed twig_length_filter() when used with UTF-8 values
566
+ * added a more useful exception if an if tag is not closed properly
567
+ * added support for escaping strategy in the autoescape tag
568
+ * fixed lexer when a template has a big chunk of text between/in a block
569
+
570
+ * 0.9.5 (2010-01-20)
571
+
572
+ As for any new release, don't forget to remove all cached templates after
573
+ upgrading.
574
+
575
+ If you have defined custom filters, you MUST upgrade them for this release. To
576
+ upgrade, replace "array" with "new Twig_Filter_Function", and replace the
577
+ environment constant by the "needs_environment" option:
578
+
579
+ // before
580
+ 'even' => array('twig_is_even_filter', false),
581
+ 'escape' => array('twig_escape_filter', true),
582
+
583
+ // after
584
+ 'even' => new Twig_Filter_Function('twig_is_even_filter'),
585
+ 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
586
+
587
+ If you have created NodeTransformer classes, you will need to upgrade them to
588
+ the new interface (please note that the interface is not yet considered
589
+ stable).
590
+
591
+ * fixed list nodes that did not extend the Twig_NodeListInterface
592
+ * added the "without loop" option to the for tag (it disables the generation of the loop variable)
593
+ * refactored node transformers to node visitors
594
+ * fixed automatic-escaping for blocks
595
+ * added a way to specify variables to pass to an included template
596
+ * changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
597
+ * improved the filter system to allow object methods to be used as filters
598
+ * changed the Array and String loaders to actually make use of the cache mechanism
599
+ * included the default filter function definitions in the extension class files directly (Core, Escaper)
600
+ * added the // operator (like the floor() PHP function)
601
+ * added the .. operator (as a syntactic sugar for the range filter when the step is 1)
602
+ * added the in operator (as a syntactic sugar for the in filter)
603
+ * added the following filters in the Core extension: in, range
604
+ * added support for arrays (same behavior as in PHP, a mix between lists and dictionaries, arrays and hashes)
605
+ * enhanced some error messages to provide better feedback in case of parsing errors
606
+
607
+ * 0.9.4 (2009-12-02)
608
+
609
+ If you have custom loaders, you MUST upgrade them for this release: The
610
+ Twig_Loader base class has been removed, and the Twig_LoaderInterface has also
611
+ been changed (see the source code for more information or the documentation).
612
+
613
+ * added support for DateTime instances for the date filter
614
+ * fixed loop.last when the array only has one item
615
+ * made it possible to insert newlines in tag and variable blocks
616
+ * fixed a bug when a literal '\n' were present in a template text
617
+ * fixed bug when the filename of a template contains */
618
+ * refactored loaders
619
+
620
+ * 0.9.3 (2009-11-11)
621
+
622
+ This release is NOT backward compatible with the previous releases.
623
+
624
+ The loaders do not take the cache and autoReload arguments anymore. Instead,
625
+ the Twig_Environment class has two new options: cache and auto_reload.
626
+ Upgrading your code means changing this kind of code:
627
+
628
+ $loader = new Twig_Loader_Filesystem('/path/to/templates', '/path/to/compilation_cache', true);
629
+ $twig = new Twig_Environment($loader);
630
+
631
+ to something like this:
632
+
633
+ $loader = new Twig_Loader_Filesystem('/path/to/templates');
634
+ $twig = new Twig_Environment($loader, array(
635
+ 'cache' => '/path/to/compilation_cache',
636
+ 'auto_reload' => true,
637
+ ));
638
+
639
+ * deprecated the "items" filter as it is not needed anymore
640
+ * made cache and auto_reload options of Twig_Environment instead of arguments of Twig_Loader
641
+ * optimized template loading speed
642
+ * removed output when an error occurs in a template and render() is used
643
+ * made major speed improvements for loops (up to 300% on even the smallest loops)
644
+ * added properties as part of the sandbox mode
645
+ * added public properties support (obj.item can now be the item property on the obj object)
646
+ * extended set tag to support expression as value ({% set foo as 'foo' ~ 'bar' %} )
647
+ * fixed bug when \ was used in HTML
648
+
649
+ * 0.9.2 (2009-10-29)
650
+
651
+ * made some speed optimizations
652
+ * changed the cache extension to .php
653
+ * added a js escaping strategy
654
+ * added support for short block tag
655
+ * changed the filter tag to allow chained filters
656
+ * made lexer more flexible as you can now change the default delimiters
657
+ * added set tag
658
+ * changed default directory permission when cache dir does not exist (more secure)
659
+ * added macro support
660
+ * changed filters first optional argument to be a Twig_Environment instance instead of a Twig_Template instance
661
+ * made Twig_Autoloader::autoload() a static method
662
+ * avoid writing template file if an error occurs
663
+ * added $ escaping when outputting raw strings
664
+ * enhanced some error messages to ease debugging
665
+ * fixed empty cache files when the template contains an error
666
+
667
+ * 0.9.1 (2009-10-14)
668
+
669
+ * fixed a bug in PHP 5.2.6
670
+ * fixed numbers with one than one decimal
671
+ * added support for method calls with arguments ({{ foo.bar('a', 43) }})
672
+ * made small speed optimizations
673
+ * made minor tweaks to allow better extensibility and flexibility
674
+
675
+ * 0.9.0 (2009-10-12)
676
+
677
+ * Initial release
vendor/vendor/twig/twig/LICENSE ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2009-2014 by the Twig Team.
2
+
3
+ Some rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following
14
+ disclaimer in the documentation and/or other materials provided
15
+ with the distribution.
16
+
17
+ * The names of the contributors may not be used to endorse or
18
+ promote products derived from this software without specific
19
+ prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
vendor/vendor/twig/twig/README.rst ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig, the flexible, fast, and secure template language for PHP
2
+ ==============================================================
3
+
4
+ Twig is a template language for PHP, released under the new BSD license (code
5
+ and documentation).
6
+
7
+ Twig uses a syntax similar to the Django and Jinja template languages which
8
+ inspired the Twig runtime environment.
9
+
10
+ More Information
11
+ ----------------
12
+
13
+ Read the `documentation`_ for more information.
14
+
15
+ .. _documentation: http://twig.sensiolabs.org/documentation
vendor/vendor/twig/twig/composer.json ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": "https://github.com/fabpot/Twig/graphs/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.4"
31
+ },
32
+ "autoload": {
33
+ "psr-0" : {
34
+ "Twig_" : "lib/"
35
+ }
36
+ },
37
+ "extra": {
38
+ "branch-alias": {
39
+ "dev-master": "1.15-dev"
40
+ }
41
+ }
42
+ }
vendor/vendor/twig/twig/doc/advanced.rst ADDED
@@ -0,0 +1,834 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 method
140
+ $filter = new Twig_SimpleFilter('rot13', array('SomeClass', 'rot13Filter'));
141
+
142
+ The first argument passed to the ``Twig_SimpleFilter`` constructor is the name
143
+ of the filter you will use in templates and the second one is the PHP callable
144
+ to associate with it.
145
+
146
+ Then, add the filter to your Twig environment::
147
+
148
+ $twig = new Twig_Environment($loader);
149
+ $twig->addFilter($filter);
150
+
151
+ And here is how to use it in a template:
152
+
153
+ .. code-block:: jinja
154
+
155
+ {{ 'Twig'|rot13 }}
156
+
157
+ {# will output Gjvt #}
158
+
159
+ When called by Twig, the PHP callable receives the left side of the filter
160
+ (before the pipe ``|``) as the first argument and the extra arguments passed
161
+ to the filter (within parentheses ``()``) as extra arguments.
162
+
163
+ For instance, the following code:
164
+
165
+ .. code-block:: jinja
166
+
167
+ {{ 'TWIG'|lower }}
168
+ {{ now|date('d/m/Y') }}
169
+
170
+ is compiled to something like the following::
171
+
172
+ <?php echo strtolower('TWIG') ?>
173
+ <?php echo twig_date_format_filter($now, 'd/m/Y') ?>
174
+
175
+ The ``Twig_SimpleFilter`` class takes an array of options as its last
176
+ argument::
177
+
178
+ $filter = new Twig_SimpleFilter('rot13', 'str_rot13', $options);
179
+
180
+ Environment-aware Filters
181
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
182
+
183
+ If you want to access the current environment instance in your filter, set the
184
+ ``needs_environment`` option to ``true``; Twig will pass the current
185
+ environment as the first argument to the filter call::
186
+
187
+ $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $string) {
188
+ // get the current charset for instance
189
+ $charset = $env->getCharset();
190
+
191
+ return str_rot13($string);
192
+ }, array('needs_environment' => true));
193
+
194
+ Context-aware Filters
195
+ ~~~~~~~~~~~~~~~~~~~~~
196
+
197
+ If you want to access the current context in your filter, set the
198
+ ``needs_context`` option to ``true``; Twig will pass the current context as
199
+ the first argument to the filter call (or the second one if
200
+ ``needs_environment`` is also set to ``true``)::
201
+
202
+ $filter = new Twig_SimpleFilter('rot13', function ($context, $string) {
203
+ // ...
204
+ }, array('needs_context' => true));
205
+
206
+ $filter = new Twig_SimpleFilter('rot13', function (Twig_Environment $env, $context, $string) {
207
+ // ...
208
+ }, array('needs_context' => true, 'needs_environment' => true));
209
+
210
+ Automatic Escaping
211
+ ~~~~~~~~~~~~~~~~~~
212
+
213
+ If automatic escaping is enabled, the output of the filter may be escaped
214
+ before printing. If your filter acts as an escaper (or explicitly outputs HTML
215
+ or JavaScript code), you will want the raw output to be printed. In such a
216
+ case, set the ``is_safe`` option::
217
+
218
+ $filter = new Twig_SimpleFilter('nl2br', 'nl2br', array('is_safe' => array('html')));
219
+
220
+ Some filters may need to work on input that is already escaped or safe, for
221
+ example when adding (safe) HTML tags to originally unsafe output. In such a
222
+ case, set the ``pre_escape`` option to escape the input data before it is run
223
+ through your filter::
224
+
225
+ $filter = new Twig_SimpleFilter('somefilter', 'somefilter', array('pre_escape' => 'html', 'is_safe' => array('html')));
226
+
227
+ Dynamic Filters
228
+ ~~~~~~~~~~~~~~~
229
+
230
+ A filter name containing the special ``*`` character is a dynamic filter as
231
+ the ``*`` can be any string::
232
+
233
+ $filter = new Twig_SimpleFilter('*_path', function ($name, $arguments) {
234
+ // ...
235
+ });
236
+
237
+ The following filters will be matched by the above defined dynamic filter:
238
+
239
+ * ``product_path``
240
+ * ``category_path``
241
+
242
+ A dynamic filter can define more than one dynamic parts::
243
+
244
+ $filter = new Twig_SimpleFilter('*_path_*', function ($name, $suffix, $arguments) {
245
+ // ...
246
+ });
247
+
248
+ The filter will receive all dynamic part values before the normal filter
249
+ arguments, but after the environment and the context. For instance, a call to
250
+ ``'foo'|a_path_b()`` will result in the following arguments to be passed to
251
+ the filter: ``('a', 'b', 'foo')``.
252
+
253
+ Functions
254
+ ---------
255
+
256
+ Functions are defined in the exact same way as filters, but you need to create
257
+ an instance of ``Twig_SimpleFunction``::
258
+
259
+ $twig = new Twig_Environment($loader);
260
+ $function = new Twig_SimpleFunction('function_name', function () {
261
+ // ...
262
+ });
263
+ $twig->addFunction($function);
264
+
265
+ Functions support the same features as filters, except for the ``pre_escape``
266
+ and ``preserves_safety`` options.
267
+
268
+ Tests
269
+ -----
270
+
271
+ Tests are defined in the exact same way as filters and functions, but you need
272
+ to create an instance of ``Twig_SimpleTest``::
273
+
274
+ $twig = new Twig_Environment($loader);
275
+ $test = new Twig_SimpleTest('test_name', function () {
276
+ // ...
277
+ });
278
+ $twig->addTest($test);
279
+
280
+ Tests allow you to create custom application specific logic for evaluating
281
+ boolean conditions. As a simple example, let's create a Twig test that checks if
282
+ objects are 'red'::
283
+
284
+ $twig = new Twig_Environment($loader)
285
+ $test = new Twig_SimpleTest('red', function ($value) {
286
+ if (isset($value->color) && $value->color == 'red') {
287
+ return true;
288
+ }
289
+ if (isset($value->paint) && $value->paint == 'red') {
290
+ return true;
291
+ }
292
+ return false;
293
+ });
294
+ $twig->addTest($test);
295
+
296
+ Test functions should always return true/false.
297
+
298
+ When creating tests you can use the ``node_class`` option to provide custom test
299
+ compilation. This is useful if your test can be compiled into PHP primitives.
300
+ This is used by many of the tests built into Twig::
301
+
302
+ $twig = new Twig_Environment($loader)
303
+ $test = new Twig_SimpleTest(
304
+ 'odd',
305
+ null,
306
+ array('node_class' => 'Twig_Node_Expression_Test_Odd'));
307
+ $twig->addTest($test);
308
+
309
+ class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
310
+ {
311
+ public function compile(Twig_Compiler $compiler)
312
+ {
313
+ $compiler
314
+ ->raw('(')
315
+ ->subcompile($this->getNode('node'))
316
+ ->raw(' % 2 == 1')
317
+ ->raw(')')
318
+ ;
319
+ }
320
+ }
321
+
322
+ The above example shows how you can create tests that use a node class. The
323
+ node class has access to one sub-node called 'node'. This sub-node contains the
324
+ value that is being tested. When the ``odd`` filter is used in code such as:
325
+
326
+ .. code-block:: jinja
327
+
328
+ {% if my_value is odd %}
329
+
330
+ The ``node`` sub-node will contain an expression of ``my_value``. Node-based
331
+ tests also have access to the ``arguments`` node. This node will contain the
332
+ various other arguments that have been provided to your test.
333
+
334
+ Tags
335
+ ----
336
+
337
+ One of the most exciting features of a template engine like Twig is the
338
+ possibility to define new language constructs. This is also the most complex
339
+ feature as you need to understand how Twig's internals work.
340
+
341
+ Let's create a simple ``set`` tag that allows the definition of simple
342
+ variables from within a template. The tag can be used like follows:
343
+
344
+ .. code-block:: jinja
345
+
346
+ {% set name = "value" %}
347
+
348
+ {{ name }}
349
+
350
+ {# should output value #}
351
+
352
+ .. note::
353
+
354
+ The ``set`` tag is part of the Core extension and as such is always
355
+ available. The built-in version is slightly more powerful and supports
356
+ multiple assignments by default (cf. the template designers chapter for
357
+ more information).
358
+
359
+ Three steps are needed to define a new tag:
360
+
361
+ * Defining a Token Parser class (responsible for parsing the template code);
362
+
363
+ * Defining a Node class (responsible for converting the parsed code to PHP);
364
+
365
+ * Registering the tag.
366
+
367
+ Registering a new tag
368
+ ~~~~~~~~~~~~~~~~~~~~~
369
+
370
+ Adding a tag is as simple as calling the ``addTokenParser`` method on the
371
+ ``Twig_Environment`` instance::
372
+
373
+ $twig = new Twig_Environment($loader);
374
+ $twig->addTokenParser(new Project_Set_TokenParser());
375
+
376
+ Defining a Token Parser
377
+ ~~~~~~~~~~~~~~~~~~~~~~~
378
+
379
+ Now, let's see the actual code of this class::
380
+
381
+ class Project_Set_TokenParser extends Twig_TokenParser
382
+ {
383
+ public function parse(Twig_Token $token)
384
+ {
385
+ $parser = $this->parser;
386
+ $stream = $parser->getStream();
387
+
388
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
389
+ $stream->expect(Twig_Token::OPERATOR_TYPE, '=');
390
+ $value = $parser->getExpressionParser()->parseExpression();
391
+ $stream->expect(Twig_Token::BLOCK_END_TYPE);
392
+
393
+ return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag());
394
+ }
395
+
396
+ public function getTag()
397
+ {
398
+ return 'set';
399
+ }
400
+ }
401
+
402
+ The ``getTag()`` method must return the tag we want to parse, here ``set``.
403
+
404
+ The ``parse()`` method is invoked whenever the parser encounters a ``set``
405
+ tag. It should return a ``Twig_Node`` instance that represents the node (the
406
+ ``Project_Set_Node`` calls creating is explained in the next section).
407
+
408
+ The parsing process is simplified thanks to a bunch of methods you can call
409
+ from the token stream (``$this->parser->getStream()``):
410
+
411
+ * ``getCurrent()``: Gets the current token in the stream.
412
+
413
+ * ``next()``: Moves to the next token in the stream, *but returns the old one*.
414
+
415
+ * ``test($type)``, ``test($value)`` or ``test($type, $value)``: Determines whether
416
+ the current token is of a particular type or value (or both). The value may be an
417
+ array of several possible values.
418
+
419
+ * ``expect($type[, $value[, $message]])``: If the current token isn't of the given
420
+ type/value a syntax error is thrown. Otherwise, if the type and value are correct,
421
+ the token is returned and the stream moves to the next token.
422
+
423
+ * ``look()``: Looks a the next token without consuming it.
424
+
425
+ Parsing expressions is done by calling the ``parseExpression()`` like we did for
426
+ the ``set`` tag.
427
+
428
+ .. tip::
429
+
430
+ Reading the existing ``TokenParser`` classes is the best way to learn all
431
+ the nitty-gritty details of the parsing process.
432
+
433
+ Defining a Node
434
+ ~~~~~~~~~~~~~~~
435
+
436
+ The ``Project_Set_Node`` class itself is rather simple::
437
+
438
+ class Project_Set_Node extends Twig_Node
439
+ {
440
+ public function __construct($name, Twig_Node_Expression $value, $line, $tag = null)
441
+ {
442
+ parent::__construct(array('value' => $value), array('name' => $name), $line, $tag);
443
+ }
444
+
445
+ public function compile(Twig_Compiler $compiler)
446
+ {
447
+ $compiler
448
+ ->addDebugInfo($this)
449
+ ->write('$context[\''.$this->getAttribute('name').'\'] = ')
450
+ ->subcompile($this->getNode('value'))
451
+ ->raw(";\n")
452
+ ;
453
+ }
454
+ }
455
+
456
+ The compiler implements a fluid interface and provides methods that helps the
457
+ developer generate beautiful and readable PHP code:
458
+
459
+ * ``subcompile()``: Compiles a node.
460
+
461
+ * ``raw()``: Writes the given string as is.
462
+
463
+ * ``write()``: Writes the given string by adding indentation at the beginning
464
+ of each line.
465
+
466
+ * ``string()``: Writes a quoted string.
467
+
468
+ * ``repr()``: Writes a PHP representation of a given value (see
469
+ ``Twig_Node_For`` for a usage example).
470
+
471
+ * ``addDebugInfo()``: Adds the line of the original template file related to
472
+ the current node as a comment.
473
+
474
+ * ``indent()``: Indents the generated code (see ``Twig_Node_Block`` for a
475
+ usage example).
476
+
477
+ * ``outdent()``: Outdents the generated code (see ``Twig_Node_Block`` for a
478
+ usage example).
479
+
480
+ .. _creating_extensions:
481
+
482
+ Creating an Extension
483
+ ---------------------
484
+
485
+ The main motivation for writing an extension is to move often used code into a
486
+ reusable class like adding support for internationalization. An extension can
487
+ define tags, filters, tests, operators, global variables, functions, and node
488
+ visitors.
489
+
490
+ Creating an extension also makes for a better separation of code that is
491
+ executed at compilation time and code needed at runtime. As such, it makes
492
+ your code faster.
493
+
494
+ Most of the time, it is useful to create a single extension for your project,
495
+ to host all the specific tags and filters you want to add to Twig.
496
+
497
+ .. tip::
498
+
499
+ When packaging your code into an extension, Twig is smart enough to
500
+ recompile your templates whenever you make a change to it (when
501
+ ``auto_reload`` is enabled).
502
+
503
+ .. note::
504
+
505
+ Before writing your own extensions, have a look at the Twig official
506
+ extension repository: http://github.com/fabpot/Twig-extensions.
507
+
508
+ An extension is a class that implements the following interface::
509
+
510
+ interface Twig_ExtensionInterface
511
+ {
512
+ /**
513
+ * Initializes the runtime environment.
514
+ *
515
+ * This is where you can load some file that contains filter functions for instance.
516
+ *
517
+ * @param Twig_Environment $environment The current Twig_Environment instance
518
+ */
519
+ function initRuntime(Twig_Environment $environment);
520
+
521
+ /**
522
+ * Returns the token parser instances to add to the existing list.
523
+ *
524
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
525
+ */
526
+ function getTokenParsers();
527
+
528
+ /**
529
+ * Returns the node visitor instances to add to the existing list.
530
+ *
531
+ * @return array An array of Twig_NodeVisitorInterface instances
532
+ */
533
+ function getNodeVisitors();
534
+
535
+ /**
536
+ * Returns a list of filters to add to the existing list.
537
+ *
538
+ * @return array An array of filters
539
+ */
540
+ function getFilters();
541
+
542
+ /**
543
+ * Returns a list of tests to add to the existing list.
544
+ *
545
+ * @return array An array of tests
546
+ */
547
+ function getTests();
548
+
549
+ /**
550
+ * Returns a list of functions to add to the existing list.
551
+ *
552
+ * @return array An array of functions
553
+ */
554
+ function getFunctions();
555
+
556
+ /**
557
+ * Returns a list of operators to add to the existing list.
558
+ *
559
+ * @return array An array of operators
560
+ */
561
+ function getOperators();
562
+
563
+ /**
564
+ * Returns a list of global variables to add to the existing list.
565
+ *
566
+ * @return array An array of global variables
567
+ */
568
+ function getGlobals();
569
+
570
+ /**
571
+ * Returns the name of the extension.
572
+ *
573
+ * @return string The extension name
574
+ */
575
+ function getName();
576
+ }
577
+
578
+ To keep your extension class clean and lean, it can inherit from the built-in
579
+ ``Twig_Extension`` class instead of implementing the whole interface. That
580
+ way, you just need to implement the ``getName()`` method as the
581
+ ``Twig_Extension`` provides empty implementations for all other methods.
582
+
583
+ The ``getName()`` method must return a unique identifier for your extension.
584
+
585
+ Now, with this information in mind, let's create the most basic extension
586
+ possible::
587
+
588
+ class Project_Twig_Extension extends Twig_Extension
589
+ {
590
+ public function getName()
591
+ {
592
+ return 'project';
593
+ }
594
+ }
595
+
596
+ .. note::
597
+
598
+ Of course, this extension does nothing for now. We will customize it in
599
+ the next sections.
600
+
601
+ Twig does not care where you save your extension on the filesystem, as all
602
+ extensions must be registered explicitly to be available in your templates.
603
+
604
+ You can register an extension by using the ``addExtension()`` method on your
605
+ main ``Environment`` object::
606
+
607
+ $twig = new Twig_Environment($loader);
608
+ $twig->addExtension(new Project_Twig_Extension());
609
+
610
+ Of course, you need to first load the extension file by either using
611
+ ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
612
+
613
+ .. tip::
614
+
615
+ The bundled extensions are great examples of how extensions work.
616
+
617
+ Globals
618
+ ~~~~~~~
619
+
620
+ Global variables can be registered in an extension via the ``getGlobals()``
621
+ method::
622
+
623
+ class Project_Twig_Extension extends Twig_Extension
624
+ {
625
+ public function getGlobals()
626
+ {
627
+ return array(
628
+ 'text' => new Text(),
629
+ );
630
+ }
631
+
632
+ // ...
633
+ }
634
+
635
+ Functions
636
+ ~~~~~~~~~
637
+
638
+ Functions can be registered in an extension via the ``getFunctions()``
639
+ method::
640
+
641
+ class Project_Twig_Extension extends Twig_Extension
642
+ {
643
+ public function getFunctions()
644
+ {
645
+ return array(
646
+ new Twig_SimpleFunction('lipsum', 'generate_lipsum'),
647
+ );
648
+ }
649
+
650
+ // ...
651
+ }
652
+
653
+ Filters
654
+ ~~~~~~~
655
+
656
+ To add a filter to an extension, you need to override the ``getFilters()``
657
+ method. This method must return an array of filters to add to the Twig
658
+ environment::
659
+
660
+ class Project_Twig_Extension extends Twig_Extension
661
+ {
662
+ public function getFilters()
663
+ {
664
+ return array(
665
+ new Twig_SimpleFilter('rot13', 'str_rot13'),
666
+ );
667
+ }
668
+
669
+ // ...
670
+ }
671
+
672
+ Tags
673
+ ~~~~
674
+
675
+ Adding a tag in an extension can be done by overriding the
676
+ ``getTokenParsers()`` method. This method must return an array of tags to add
677
+ to the Twig environment::
678
+
679
+ class Project_Twig_Extension extends Twig_Extension
680
+ {
681
+ public function getTokenParsers()
682
+ {
683
+ return array(new Project_Set_TokenParser());
684
+ }
685
+
686
+ // ...
687
+ }
688
+
689
+ In the above code, we have added a single new tag, defined by the
690
+ ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
691
+ responsible for parsing the tag and compiling it to PHP.
692
+
693
+ Operators
694
+ ~~~~~~~~~
695
+
696
+ The ``getOperators()`` methods lets you add new operators. Here is how to add
697
+ ``!``, ``||``, and ``&&`` operators::
698
+
699
+ class Project_Twig_Extension extends Twig_Extension
700
+ {
701
+ public function getOperators()
702
+ {
703
+ return array(
704
+ array(
705
+ '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
706
+ ),
707
+ array(
708
+ '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
709
+ '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
710
+ ),
711
+ );
712
+ }
713
+
714
+ // ...
715
+ }
716
+
717
+ Tests
718
+ ~~~~~
719
+
720
+ The ``getTests()`` method lets you add new test functions::
721
+
722
+ class Project_Twig_Extension extends Twig_Extension
723
+ {
724
+ public function getTests()
725
+ {
726
+ return array(
727
+ new Twig_SimpleTest('even', 'twig_test_even'),
728
+ );
729
+ }
730
+
731
+ // ...
732
+ }
733
+
734
+ Overloading
735
+ -----------
736
+
737
+ To overload an already defined filter, test, operator, global variable, or
738
+ function, re-define it in an extension and register it **as late as
739
+ possible** (order matters)::
740
+
741
+ class MyCoreExtension extends Twig_Extension
742
+ {
743
+ public function getFilters()
744
+ {
745
+ return array(
746
+ new Twig_SimpleFilter('date', array($this, 'dateFilter')),
747
+ );
748
+ }
749
+
750
+ public function dateFilter($timestamp, $format = 'F j, Y H:i')
751
+ {
752
+ // do something different from the built-in date filter
753
+ }
754
+
755
+ public function getName()
756
+ {
757
+ return 'project';
758
+ }
759
+ }
760
+
761
+ $twig = new Twig_Environment($loader);
762
+ $twig->addExtension(new MyCoreExtension());
763
+
764
+ Here, we have overloaded the built-in ``date`` filter with a custom one.
765
+
766
+ If you do the same on the Twig_Environment itself, beware that it takes
767
+ precedence over any other registered extensions::
768
+
769
+ $twig = new Twig_Environment($loader);
770
+ $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') {
771
+ // do something different from the built-in date filter
772
+ }));
773
+ // the date filter will come from the above registration, not
774
+ // from the registered extension below
775
+ $twig->addExtension(new MyCoreExtension());
776
+
777
+ .. caution::
778
+
779
+ Note that overloading the built-in Twig elements is not recommended as it
780
+ might be confusing.
781
+
782
+ Testing an Extension
783
+ --------------------
784
+
785
+ Functional Tests
786
+ ~~~~~~~~~~~~~~~~
787
+
788
+ You can create functional tests for extensions simply by creating the
789
+ following file structure in your test directory::
790
+
791
+ Fixtures/
792
+ filters/
793
+ foo.test
794
+ bar.test
795
+ functions/
796
+ foo.test
797
+ bar.test
798
+ tags/
799
+ foo.test
800
+ bar.test
801
+ IntegrationTest.php
802
+
803
+ The ``IntegrationTest.php`` file should look like this::
804
+
805
+ class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
806
+ {
807
+ public function getExtensions()
808
+ {
809
+ return array(
810
+ new Project_Twig_Extension1(),
811
+ new Project_Twig_Extension2(),
812
+ );
813
+ }
814
+
815
+ public function getFixturesDir()
816
+ {
817
+ return dirname(__FILE__).'/Fixtures/';
818
+ }
819
+ }
820
+
821
+ Fixtures examples can be found within the Twig repository
822
+ `tests/Twig/Fixtures`_ directory.
823
+
824
+ Node Tests
825
+ ~~~~~~~~~~
826
+
827
+ Testing the node visitors can be complex, so extend your test cases from
828
+ ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
829
+ `tests/Twig/Node`_ directory.
830
+
831
+ .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
832
+ .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
833
+ .. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
834
+ .. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node
vendor/vendor/twig/twig/doc/advanced_legacy.rst ADDED
@@ -0,0 +1,887 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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/fabpot/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
+ * @param Twig_Environment $environment The current Twig_Environment instance
544
+ */
545
+ function initRuntime(Twig_Environment $environment);
546
+
547
+ /**
548
+ * Returns the token parser instances to add to the existing list.
549
+ *
550
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
551
+ */
552
+ function getTokenParsers();
553
+
554
+ /**
555
+ * Returns the node visitor instances to add to the existing list.
556
+ *
557
+ * @return array An array of Twig_NodeVisitorInterface instances
558
+ */
559
+ function getNodeVisitors();
560
+
561
+ /**
562
+ * Returns a list of filters to add to the existing list.
563
+ *
564
+ * @return array An array of filters
565
+ */
566
+ function getFilters();
567
+
568
+ /**
569
+ * Returns a list of tests to add to the existing list.
570
+ *
571
+ * @return array An array of tests
572
+ */
573
+ function getTests();
574
+
575
+ /**
576
+ * Returns a list of functions to add to the existing list.
577
+ *
578
+ * @return array An array of functions
579
+ */
580
+ function getFunctions();
581
+
582
+ /**
583
+ * Returns a list of operators to add to the existing list.
584
+ *
585
+ * @return array An array of operators
586
+ */
587
+ function getOperators();
588
+
589
+ /**
590
+ * Returns a list of global variables to add to the existing list.
591
+ *
592
+ * @return array An array of global variables
593
+ */
594
+ function getGlobals();
595
+
596
+ /**
597
+ * Returns the name of the extension.
598
+ *
599
+ * @return string The extension name
600
+ */
601
+ function getName();
602
+ }
603
+
604
+ To keep your extension class clean and lean, it can inherit from the built-in
605
+ ``Twig_Extension`` class instead of implementing the whole interface. That
606
+ way, you just need to implement the ``getName()`` method as the
607
+ ``Twig_Extension`` provides empty implementations for all other methods.
608
+
609
+ The ``getName()`` method must return a unique identifier for your extension.
610
+
611
+ Now, with this information in mind, let's create the most basic extension
612
+ possible::
613
+
614
+ class Project_Twig_Extension extends Twig_Extension
615
+ {
616
+ public function getName()
617
+ {
618
+ return 'project';
619
+ }
620
+ }
621
+
622
+ .. note::
623
+
624
+ Of course, this extension does nothing for now. We will customize it in
625
+ the next sections.
626
+
627
+ Twig does not care where you save your extension on the filesystem, as all
628
+ extensions must be registered explicitly to be available in your templates.
629
+
630
+ You can register an extension by using the ``addExtension()`` method on your
631
+ main ``Environment`` object::
632
+
633
+ $twig = new Twig_Environment($loader);
634
+ $twig->addExtension(new Project_Twig_Extension());
635
+
636
+ Of course, you need to first load the extension file by either using
637
+ ``require_once()`` or by using an autoloader (see `spl_autoload_register()`_).
638
+
639
+ .. tip::
640
+
641
+ The bundled extensions are great examples of how extensions work.
642
+
643
+ Globals
644
+ ~~~~~~~
645
+
646
+ Global variables can be registered in an extension via the ``getGlobals()``
647
+ method::
648
+
649
+ class Project_Twig_Extension extends Twig_Extension
650
+ {
651
+ public function getGlobals()
652
+ {
653
+ return array(
654
+ 'text' => new Text(),
655
+ );
656
+ }
657
+
658
+ // ...
659
+ }
660
+
661
+ Functions
662
+ ~~~~~~~~~
663
+
664
+ Functions can be registered in an extension via the ``getFunctions()``
665
+ method::
666
+
667
+ class Project_Twig_Extension extends Twig_Extension
668
+ {
669
+ public function getFunctions()
670
+ {
671
+ return array(
672
+ 'lipsum' => new Twig_Function_Function('generate_lipsum'),
673
+ );
674
+ }
675
+
676
+ // ...
677
+ }
678
+
679
+ Filters
680
+ ~~~~~~~
681
+
682
+ To add a filter to an extension, you need to override the ``getFilters()``
683
+ method. This method must return an array of filters to add to the Twig
684
+ environment::
685
+
686
+ class Project_Twig_Extension extends Twig_Extension
687
+ {
688
+ public function getFilters()
689
+ {
690
+ return array(
691
+ 'rot13' => new Twig_Filter_Function('str_rot13'),
692
+ );
693
+ }
694
+
695
+ // ...
696
+ }
697
+
698
+ As you can see in the above code, the ``getFilters()`` method returns an array
699
+ where keys are the name of the filters (``rot13``) and the values the
700
+ definition of the filter (``new Twig_Filter_Function('str_rot13')``).
701
+
702
+ As seen in the previous chapter, you can also define filters as static methods
703
+ on the extension class::
704
+
705
+ $twig->addFilter('rot13', new Twig_Filter_Function('Project_Twig_Extension::rot13Filter'));
706
+
707
+ You can also use ``Twig_Filter_Method`` instead of ``Twig_Filter_Function``
708
+ when defining a filter to use a method::
709
+
710
+ class Project_Twig_Extension extends Twig_Extension
711
+ {
712
+ public function getFilters()
713
+ {
714
+ return array(
715
+ 'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
716
+ );
717
+ }
718
+
719
+ public function rot13Filter($string)
720
+ {
721
+ return str_rot13($string);
722
+ }
723
+
724
+ // ...
725
+ }
726
+
727
+ The first argument of the ``Twig_Filter_Method`` constructor is always
728
+ ``$this``, the current extension object. The second one is the name of the
729
+ method to call.
730
+
731
+ Using methods for filters is a great way to package your filter without
732
+ polluting the global namespace. This also gives the developer more flexibility
733
+ at the cost of a small overhead.
734
+
735
+ Overriding default Filters
736
+ ..........................
737
+
738
+ If some default core filters do not suit your needs, you can easily override
739
+ them by creating your own extension. Just use the same names as the one you
740
+ want to override::
741
+
742
+ class MyCoreExtension extends Twig_Extension
743
+ {
744
+ public function getFilters()
745
+ {
746
+ return array(
747
+ 'date' => new Twig_Filter_Method($this, 'dateFilter'),
748
+ // ...
749
+ );
750
+ }
751
+
752
+ public function dateFilter($timestamp, $format = 'F j, Y H:i')
753
+ {
754
+ return '...'.twig_date_format_filter($timestamp, $format);
755
+ }
756
+
757
+ public function getName()
758
+ {
759
+ return 'project';
760
+ }
761
+ }
762
+
763
+ Here, we override the ``date`` filter with a custom one. Using this extension
764
+ is as simple as registering the ``MyCoreExtension`` extension by calling the
765
+ ``addExtension()`` method on the environment instance::
766
+
767
+ $twig = new Twig_Environment($loader);
768
+ $twig->addExtension(new MyCoreExtension());
769
+
770
+ Tags
771
+ ~~~~
772
+
773
+ Adding a tag in an extension can be done by overriding the
774
+ ``getTokenParsers()`` method. This method must return an array of tags to add
775
+ to the Twig environment::
776
+
777
+ class Project_Twig_Extension extends Twig_Extension
778
+ {
779
+ public function getTokenParsers()
780
+ {
781
+ return array(new Project_Set_TokenParser());
782
+ }
783
+
784
+ // ...
785
+ }
786
+
787
+ In the above code, we have added a single new tag, defined by the
788
+ ``Project_Set_TokenParser`` class. The ``Project_Set_TokenParser`` class is
789
+ responsible for parsing the tag and compiling it to PHP.
790
+
791
+ Operators
792
+ ~~~~~~~~~
793
+
794
+ The ``getOperators()`` methods allows to add new operators. Here is how to add
795
+ ``!``, ``||``, and ``&&`` operators::
796
+
797
+ class Project_Twig_Extension extends Twig_Extension
798
+ {
799
+ public function getOperators()
800
+ {
801
+ return array(
802
+ array(
803
+ '!' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
804
+ ),
805
+ array(
806
+ '||' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
807
+ '&&' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
808
+ ),
809
+ );
810
+ }
811
+
812
+ // ...
813
+ }
814
+
815
+ Tests
816
+ ~~~~~
817
+
818
+ The ``getTests()`` methods allows to add new test functions::
819
+
820
+ class Project_Twig_Extension extends Twig_Extension
821
+ {
822
+ public function getTests()
823
+ {
824
+ return array(
825
+ 'even' => new Twig_Test_Function('twig_test_even'),
826
+ );
827
+ }
828
+
829
+ // ...
830
+ }
831
+
832
+ Testing an Extension
833
+ --------------------
834
+
835
+ .. versionadded:: 1.10
836
+ Support for functional tests was added in Twig 1.10.
837
+
838
+ Functional Tests
839
+ ~~~~~~~~~~~~~~~~
840
+
841
+ You can create functional tests for extensions simply by creating the
842
+ following file structure in your test directory::
843
+
844
+ Fixtures/
845
+ filters/
846
+ foo.test
847
+ bar.test
848
+ functions/
849
+ foo.test
850
+ bar.test
851
+ tags/
852
+ foo.test
853
+ bar.test
854
+ IntegrationTest.php
855
+
856
+ The ``IntegrationTest.php`` file should look like this::
857
+
858
+ class Project_Tests_IntegrationTest extends Twig_Test_IntegrationTestCase
859
+ {
860
+ public function getExtensions()
861
+ {
862
+ return array(
863
+ new Project_Twig_Extension1(),
864
+ new Project_Twig_Extension2(),
865
+ );
866
+ }
867
+
868
+ public function getFixturesDir()
869
+ {
870
+ return dirname(__FILE__).'/Fixtures/';
871
+ }
872
+ }
873
+
874
+ Fixtures examples can be found within the Twig repository
875
+ `tests/Twig/Fixtures`_ directory.
876
+
877
+ Node Tests
878
+ ~~~~~~~~~~
879
+
880
+ Testing the node visitors can be complex, so extend your test cases from
881
+ ``Twig_Test_NodeTestCase``. Examples can be found in the Twig repository
882
+ `tests/Twig/Node`_ directory.
883
+
884
+ .. _`spl_autoload_register()`: http://www.php.net/spl_autoload_register
885
+ .. _`rot13`: http://www.php.net/manual/en/function.str-rot13.php
886
+ .. _`tests/Twig/Fixtures`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Fixtures
887
+ .. _`tests/Twig/Node`: https://github.com/fabpot/Twig/tree/master/test/Twig/Tests/Node
vendor/vendor/twig/twig/doc/api.rst ADDED
@@ -0,0 +1,529 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ To load a template from this environment you just have to call the
47
+ ``loadTemplate()`` method which then returns a ``Twig_Template`` instance::
48
+
49
+ $template = $twig->loadTemplate('index.html');
50
+
51
+ To render the template with some variables, call the ``render()`` method::
52
+
53
+ echo $template->render(array('the' => 'variables', 'go' => 'here'));
54
+
55
+ .. note::
56
+
57
+ The ``display()`` method is a shortcut to output the template directly.
58
+
59
+ You can also load and render the template in one fell swoop::
60
+
61
+ echo $twig->render('index.html', array('the' => 'variables', 'go' => 'here'));
62
+
63
+ .. _environment_options:
64
+
65
+ Environment Options
66
+ -------------------
67
+
68
+ When creating a new ``Twig_Environment`` instance, you can pass an array of
69
+ options as the constructor second argument::
70
+
71
+ $twig = new Twig_Environment($loader, array('debug' => true));
72
+
73
+ The following options are available:
74
+
75
+ * ``debug``: When set to ``true``, the generated templates have a
76
+ ``__toString()`` method that you can use to display the generated nodes
77
+ (default to ``false``).
78
+
79
+ * ``charset``: The charset used by the templates (default to ``utf-8``).
80
+
81
+ * ``base_template_class``: The base template class to use for generated
82
+ templates (default to ``Twig_Template``).
83
+
84
+ * ``cache``: An absolute path where to store the compiled templates, or
85
+ ``false`` to disable caching (which is the default).
86
+
87
+ * ``auto_reload``: When developing with Twig, it's useful to recompile the
88
+ template whenever the source code changes. If you don't provide a value for
89
+ the ``auto_reload`` option, it will be determined automatically based on the
90
+ ``debug`` value.
91
+
92
+ * ``strict_variables``: If set to ``false``, Twig will silently ignore invalid
93
+ variables (variables and or attributes/methods that do not exist) and
94
+ replace them with a ``null`` value. When set to ``true``, Twig throws an
95
+ exception instead (default to ``false``).
96
+
97
+ * ``autoescape``: If set to ``true``, auto-escaping will be enabled by default
98
+ for all templates (default to ``true``). As of Twig 1.8, you can set the
99
+ escaping strategy to use (``html``, ``js``, ``false`` to disable).
100
+ As of Twig 1.9, you can set the escaping strategy to use (``css``, ``url``,
101
+ ``html_attr``, or a PHP callback that takes the template "filename" and must
102
+ return the escaping strategy to use -- the callback cannot be a function name
103
+ to avoid collision with built-in escaping strategies).
104
+
105
+ * ``optimizations``: A flag that indicates which optimizations to apply
106
+ (default to ``-1`` -- all optimizations are enabled; set it to ``0`` to
107
+ disable).
108
+
109
+ Loaders
110
+ -------
111
+
112
+ Loaders are responsible for loading templates from a resource such as the file
113
+ system.
114
+
115
+ Compilation Cache
116
+ ~~~~~~~~~~~~~~~~~
117
+
118
+ All template loaders can cache the compiled templates on the filesystem for
119
+ future reuse. It speeds up Twig a lot as templates are only compiled once; and
120
+ the performance boost is even larger if you use a PHP accelerator such as APC.
121
+ See the ``cache`` and ``auto_reload`` options of ``Twig_Environment`` above
122
+ for more information.
123
+
124
+ Built-in Loaders
125
+ ~~~~~~~~~~~~~~~~
126
+
127
+ Here is a list of the built-in loaders Twig provides:
128
+
129
+ ``Twig_Loader_Filesystem``
130
+ ..........................
131
+
132
+ .. versionadded:: 1.10
133
+ The ``prependPath()`` and support for namespaces were added in Twig 1.10.
134
+
135
+ ``Twig_Loader_Filesystem`` loads templates from the file system. This loader
136
+ can find templates in folders on the file system and is the preferred way to
137
+ load them::
138
+
139
+ $loader = new Twig_Loader_Filesystem($templateDir);
140
+
141
+ It can also look for templates in an array of directories::
142
+
143
+ $loader = new Twig_Loader_Filesystem(array($templateDir1, $templateDir2));
144
+
145
+ With such a configuration, Twig will first look for templates in
146
+ ``$templateDir1`` and if they do not exist, it will fallback to look for them
147
+ in the ``$templateDir2``.
148
+
149
+ You can add or prepend paths via the ``addPath()`` and ``prependPath()``
150
+ methods::
151
+
152
+ $loader->addPath($templateDir3);
153
+ $loader->prependPath($templateDir4);
154
+
155
+ The filesystem loader also supports namespaced templates. This allows to group
156
+ your templates under different namespaces which have their own template paths.
157
+
158
+ When using the ``setPaths()``, ``addPath()``, and ``prependPath()`` methods,
159
+ specify the namespace as the second argument (when not specified, these
160
+ methods act on the "main" namespace)::
161
+
162
+ $loader->addPath($templateDir, 'admin');
163
+
164
+ Namespaced templates can be accessed via the special
165
+ ``@namespace_name/template_path`` notation::
166
+
167
+ $twig->render('@admin/index.html', array());
168
+
169
+ ``Twig_Loader_String``
170
+ ......................
171
+
172
+ ``Twig_Loader_String`` loads templates from strings. It's a dummy loader as
173
+ the template reference is the template source code::
174
+
175
+ $loader = new Twig_Loader_String();
176
+ $twig = new Twig_Environment($loader);
177
+
178
+ echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
179
+
180
+ This loader should only be used for unit testing as it has severe limitations:
181
+ several tags, like ``extends`` or ``include`` do not make sense to use as the
182
+ reference to the template is the template source code itself.
183
+
184
+ ``Twig_Loader_Array``
185
+ .....................
186
+
187
+ ``Twig_Loader_Array`` loads a template from a PHP array. It's passed an array
188
+ of strings bound to template names::
189
+
190
+ $loader = new Twig_Loader_Array(array(
191
+ 'index.html' => 'Hello {{ name }}!',
192
+ ));
193
+ $twig = new Twig_Environment($loader);
194
+
195
+ echo $twig->render('index.html', array('name' => 'Fabien'));
196
+
197
+ This loader is very useful for unit testing. It can also be used for small
198
+ projects where storing all templates in a single PHP file might make sense.
199
+
200
+ .. tip::
201
+
202
+ When using the ``Array`` or ``String`` loaders with a cache mechanism, you
203
+ should know that a new cache key is generated each time a template content
204
+ "changes" (the cache key being the source code of the template). If you
205
+ don't want to see your cache grows out of control, you need to take care
206
+ of clearing the old cache file by yourself.
207
+
208
+ ``Twig_Loader_Chain``
209
+ .....................
210
+
211
+ ``Twig_Loader_Chain`` delegates the loading of templates to other loaders::
212
+
213
+ $loader1 = new Twig_Loader_Array(array(
214
+ 'base.html' => '{% block content %}{% endblock %}',
215
+ ));
216
+ $loader2 = new Twig_Loader_Array(array(
217
+ 'index.html' => '{% extends "base.twig" %}{% block content %}Hello {{ name }}{% endblock %}',
218
+ 'base.html' => 'Will never be loaded',
219
+ ));
220
+
221
+ $loader = new Twig_Loader_Chain(array($loader1, $loader2));
222
+
223
+ $twig = new Twig_Environment($loader);
224
+
225
+ When looking for a template, Twig will try each loader in turn and it will
226
+ return as soon as the template is found. When rendering the ``index.html``
227
+ template from the above example, Twig will load it with ``$loader2`` but the
228
+ ``base.html`` template will be loaded from ``$loader1``.
229
+
230
+ ``Twig_Loader_Chain`` accepts any loader that implements
231
+ ``Twig_LoaderInterface``.
232
+
233
+ .. note::
234
+
235
+ You can also add loaders via the ``addLoader()`` method.
236
+
237
+ Create your own Loader
238
+ ~~~~~~~~~~~~~~~~~~~~~~
239
+
240
+ All loaders implement the ``Twig_LoaderInterface``::
241
+
242
+ interface Twig_LoaderInterface
243
+ {
244
+ /**
245
+ * Gets the source code of a template, given its name.
246
+ *
247
+ * @param string $name string The name of the template to load
248
+ *
249
+ * @return string The template source code
250
+ */
251
+ function getSource($name);
252
+
253
+ /**
254
+ * Gets the cache key to use for the cache for a given template name.
255
+ *
256
+ * @param string $name string The name of the template to load
257
+ *
258
+ * @return string The cache key
259
+ */
260
+ function getCacheKey($name);
261
+
262
+ /**
263
+ * Returns true if the template is still fresh.
264
+ *
265
+ * @param string $name The template name
266
+ * @param timestamp $time The last modification time of the cached template
267
+ */
268
+ function isFresh($name, $time);
269
+ }
270
+
271
+ As an example, here is how the built-in ``Twig_Loader_String`` reads::
272
+
273
+ class Twig_Loader_String implements Twig_LoaderInterface
274
+ {
275
+ public function getSource($name)
276
+ {
277
+ return $name;
278
+ }
279
+
280
+ public function getCacheKey($name)
281
+ {
282
+ return $name;
283
+ }
284
+
285
+ public function isFresh($name, $time)
286
+ {
287
+ return false;
288
+ }
289
+ }
290
+
291
+ The ``isFresh()`` method must return ``true`` if the current cached template
292
+ is still fresh, given the last modification time, or ``false`` otherwise.
293
+
294
+ .. tip::
295
+
296
+ As of Twig 1.11.0, you can also implement ``Twig_ExistsLoaderInterface``
297
+ to make your loader faster when used with the chain loader.
298
+
299
+ Using Extensions
300
+ ----------------
301
+
302
+ Twig extensions are packages that add new features to Twig. Using an
303
+ extension is as simple as using the ``addExtension()`` method::
304
+
305
+ $twig->addExtension(new Twig_Extension_Sandbox());
306
+
307
+ Twig comes bundled with the following extensions:
308
+
309
+ * *Twig_Extension_Core*: Defines all the core features of Twig.
310
+
311
+ * *Twig_Extension_Escaper*: Adds automatic output-escaping and the possibility
312
+ to escape/unescape blocks of code.
313
+
314
+ * *Twig_Extension_Sandbox*: Adds a sandbox mode to the default Twig
315
+ environment, making it safe to evaluate untrusted code.
316
+
317
+ * *Twig_Extension_Optimizer*: Optimizes the node tree before compilation.
318
+
319
+ The core, escaper, and optimizer extensions do not need to be added to the
320
+ Twig environment, as they are registered by default.
321
+
322
+ Built-in Extensions
323
+ -------------------
324
+
325
+ This section describes the features added by the built-in extensions.
326
+
327
+ .. tip::
328
+
329
+ Read the chapter about extending Twig to learn how to create your own
330
+ extensions.
331
+
332
+ Core Extension
333
+ ~~~~~~~~~~~~~~
334
+
335
+ The ``core`` extension defines all the core features of Twig:
336
+
337
+ * :doc:`Tags <tags/index>`;
338
+ * :doc:`Filters <filters/index>`;
339
+ * :doc:`Functions <functions/index>`;
340
+ * :doc:`Tests <tests/index>`.
341
+
342
+ Escaper Extension
343
+ ~~~~~~~~~~~~~~~~~
344
+
345
+ The ``escaper`` extension adds automatic output escaping to Twig. It defines a
346
+ tag, ``autoescape``, and a filter, ``raw``.
347
+
348
+ When creating the escaper extension, you can switch on or off the global
349
+ output escaping strategy::
350
+
351
+ $escaper = new Twig_Extension_Escaper('html');
352
+ $twig->addExtension($escaper);
353
+
354
+ If set to ``html``, all variables in templates are escaped (using the ``html``
355
+ escaping strategy), except those using the ``raw`` filter:
356
+
357
+ .. code-block:: jinja
358
+
359
+ {{ article.to_html|raw }}
360
+
361
+ You can also change the escaping mode locally by using the ``autoescape`` tag
362
+ (see the :doc:`autoescape<tags/autoescape>` doc for the syntax used before
363
+ Twig 1.8):
364
+
365
+ .. code-block:: jinja
366
+
367
+ {% autoescape 'html' %}
368
+ {{ var }}
369
+ {{ var|raw }} {# var won't be escaped #}
370
+ {{ var|escape }} {# var won't be double-escaped #}
371
+ {% endautoescape %}
372
+
373
+ .. warning::
374
+
375
+ The ``autoescape`` tag has no effect on included files.
376
+
377
+ The escaping rules are implemented as follows:
378
+
379
+ * Literals (integers, booleans, arrays, ...) used in the template directly as
380
+ variables or filter arguments are never automatically escaped:
381
+
382
+ .. code-block:: jinja
383
+
384
+ {{ "Twig<br />" }} {# won't be escaped #}
385
+
386
+ {% set text = "Twig<br />" %}
387
+ {{ text }} {# will be escaped #}
388
+
389
+ * Expressions which the result is always a literal or a variable marked safe
390
+ are never automatically escaped:
391
+
392
+ .. code-block:: jinja
393
+
394
+ {{ foo ? "Twig<br />" : "<br />Twig" }} {# won't be escaped #}
395
+
396
+ {% set text = "Twig<br />" %}
397
+ {{ foo ? text : "<br />Twig" }} {# will be escaped #}
398
+
399
+ {% set text = "Twig<br />" %}
400
+ {{ foo ? text|raw : "<br />Twig" }} {# won't be escaped #}
401
+
402
+ {% set text = "Twig<br />" %}
403
+ {{ foo ? text|escape : "<br />Twig" }} {# the result of the expression won't be escaped #}
404
+
405
+ * Escaping is applied before printing, after any other filter is applied:
406
+
407
+ .. code-block:: jinja
408
+
409
+ {{ var|upper }} {# is equivalent to {{ var|upper|escape }} #}
410
+
411
+ * The `raw` filter should only be used at the end of the filter chain:
412
+
413
+ .. code-block:: jinja
414
+
415
+ {{ var|raw|upper }} {# will be escaped #}
416
+
417
+ {{ var|upper|raw }} {# won't be escaped #}
418
+
419
+ * Automatic escaping is not applied if the last filter in the chain is marked
420
+ safe for the current context (e.g. ``html`` or ``js``). ``escape`` and
421
+ ``escape('html')`` are marked safe for HTML, ``escape('js')`` is marked
422
+ safe for JavaScript, ``raw`` is marked safe for everything.
423
+
424
+ .. code-block:: jinja
425
+
426
+ {% autoescape 'js' %}
427
+ {{ var|escape('html') }} {# will be escaped for HTML and JavaScript #}
428
+ {{ var }} {# will be escaped for JavaScript #}
429
+ {{ var|escape('js') }} {# won't be double-escaped #}
430
+ {% endautoescape %}
431
+
432
+ .. note::
433
+
434
+ Note that autoescaping has some limitations as escaping is applied on
435
+ expressions after evaluation. For instance, when working with
436
+ concatenation, ``{{ foo|raw ~ bar }}`` won't give the expected result as
437
+ escaping is applied on the result of the concatenation, not on the
438
+ individual variables (so, the ``raw`` filter won't have any effect here).
439
+
440
+ Sandbox Extension
441
+ ~~~~~~~~~~~~~~~~~
442
+
443
+ The ``sandbox`` extension can be used to evaluate untrusted code. Access to
444
+ unsafe attributes and methods is prohibited. The sandbox security is managed
445
+ by a policy instance. By default, Twig comes with one policy class:
446
+ ``Twig_Sandbox_SecurityPolicy``. This class allows you to white-list some
447
+ tags, filters, properties, and methods::
448
+
449
+ $tags = array('if');
450
+ $filters = array('upper');
451
+ $methods = array(
452
+ 'Article' => array('getTitle', 'getBody'),
453
+ );
454
+ $properties = array(
455
+ 'Article' => array('title', 'body'),
456
+ );
457
+ $functions = array('range');
458
+ $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
459
+
460
+ With the previous configuration, the security policy will only allow usage of
461
+ the ``if`` tag, and the ``upper`` filter. Moreover, the templates will only be
462
+ able to call the ``getTitle()`` and ``getBody()`` methods on ``Article``
463
+ objects, and the ``title`` and ``body`` public properties. Everything else
464
+ won't be allowed and will generate a ``Twig_Sandbox_SecurityError`` exception.
465
+
466
+ The policy object is the first argument of the sandbox constructor::
467
+
468
+ $sandbox = new Twig_Extension_Sandbox($policy);
469
+ $twig->addExtension($sandbox);
470
+
471
+ By default, the sandbox mode is disabled and should be enabled when including
472
+ untrusted template code by using the ``sandbox`` tag:
473
+
474
+ .. code-block:: jinja
475
+
476
+ {% sandbox %}
477
+ {% include 'user.html' %}
478
+ {% endsandbox %}
479
+
480
+ You can sandbox all templates by passing ``true`` as the second argument of
481
+ the extension constructor::
482
+
483
+ $sandbox = new Twig_Extension_Sandbox($policy, true);
484
+
485
+ Optimizer Extension
486
+ ~~~~~~~~~~~~~~~~~~~
487
+
488
+ The ``optimizer`` extension optimizes the node tree before compilation::
489
+
490
+ $twig->addExtension(new Twig_Extension_Optimizer());
491
+
492
+ By default, all optimizations are turned on. You can select the ones you want
493
+ to enable by passing them to the constructor::
494
+
495
+ $optimizer = new Twig_Extension_Optimizer(Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR);
496
+
497
+ $twig->addExtension($optimizer);
498
+
499
+ Twig supports the following optimizations:
500
+
501
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL``, enables all optimizations
502
+ (this is the default value).
503
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE``, disables all optimizations.
504
+ This reduces the compilation time, but it can increase the execution time
505
+ and the consumed memory.
506
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR``, optimizes the ``for`` tag by
507
+ removing the ``loop`` variable creation whenever possible.
508
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER``, removes the ``raw``
509
+ filter whenever possible.
510
+ * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS``, simplifies the creation
511
+ and access of variables in the compiled templates whenever possible.
512
+
513
+ Exceptions
514
+ ----------
515
+
516
+ Twig can throw exceptions:
517
+
518
+ * ``Twig_Error``: The base exception for all errors.
519
+
520
+ * ``Twig_Error_Syntax``: Thrown to tell the user that there is a problem with
521
+ the template syntax.
522
+
523
+ * ``Twig_Error_Runtime``: Thrown when an error occurs at runtime (when a filter
524
+ does not exist for instance).
525
+
526
+ * ``Twig_Error_Loader``: Thrown when an error occurs during template loading.
527
+
528
+ * ``Twig_Sandbox_SecurityError``: Thrown when an unallowed tag, filter, or
529
+ method is called in a sandboxed template.
vendor/vendor/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 %}
vendor/vendor/twig/twig/doc/deprecated.rst ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ Token Parsers
9
+ -------------
10
+
11
+ * As of Twig 1.x, the token parser broker sub-system is deprecated. The
12
+ following class and interface will be removed in 2.0:
13
+
14
+ * ``Twig_TokenParserBrokerInterface``
15
+ * ``Twig_TokenParserBroker``
16
+
17
+ Extensions
18
+ ----------
19
+
20
+ * As of Twig 1.x, the ability to remove an extension is deprecated and the
21
+ ``Twig_Environment::removeExtension()`` method will be removed in 2.0.
22
+
23
+ PEAR
24
+ ----
25
+
26
+ PEAR support will be discontinued in Twig 2.0, and no PEAR packages will be
27
+ provided. Use Composer instead.
28
+
29
+ Filters
30
+ -------
31
+
32
+ * As of Twig 1.x, use ``Twig_SimpleFilter`` to add a filter. The following
33
+ classes and interfaces will be removed in 2.0:
34
+
35
+ * ``Twig_FilterInterface``
36
+ * ``Twig_FilterCallableInterface``
37
+ * ``Twig_Filter``
38
+ * ``Twig_Filter_Function``
39
+ * ``Twig_Filter_Method``
40
+ * ``Twig_Filter_Node``
41
+
42
+ * As of Twig 2.x, the ``Twig_SimpleFilter`` class is deprecated and will be
43
+ removed in Twig 3.x (use ``Twig_Filter`` instead). In Twig 2.x,
44
+ ``Twig_SimpleFilter`` is just an alias for ``Twig_Filter``.
45
+
46
+ Functions
47
+ ---------
48
+
49
+ * As of Twig 1.x, use ``Twig_SimpleFunction`` to add a function. The following
50
+ classes and interfaces will be removed in 2.0:
51
+
52
+ * ``Twig_FunctionInterface``
53
+ * ``Twig_FunctionCallableInterface``
54
+ * ``Twig_Function``
55
+ * ``Twig_Function_Function``
56
+ * ``Twig_Function_Method``
57
+ * ``Twig_Function_Node``
58
+
59
+ * As of Twig 2.x, the ``Twig_SimpleFunction`` class is deprecated and will be
60
+ removed in Twig 3.x (use ``Twig_Function`` instead). In Twig 2.x,
61
+ ``Twig_SimpleFunction`` is just an alias for ``Twig_Function``.
62
+
63
+ Tests
64
+ -----
65
+
66
+ * As of Twig 1.x, use ``Twig_SimpleTest`` to add a test. The following classes
67
+ and interfaces will be removed in 2.0:
68
+
69
+ * ``Twig_TestInterface``
70
+ * ``Twig_TestCallableInterface``
71
+ * ``Twig_Test``
72
+ * ``Twig_Test_Function``
73
+ * ``Twig_Test_Method``
74
+ * ``Twig_Test_Node``
75
+
76
+ * As of Twig 2.x, the ``Twig_SimpleTest`` class is deprecated and will be
77
+ removed in Twig 3.x (use ``Twig_Test`` instead). In Twig 2.x,
78
+ ``Twig_SimpleTest`` is just an alias for ``Twig_Test``.
79
+
80
+ * The ``sameas`` and ``divisibleby`` tests are deprecated in favor of ``same
81
+ as`` and ``divisible by`` respectively.
82
+
83
+ Interfaces
84
+ ----------
85
+
86
+ * As of Twig 2.x, the following interfaces are deprecated and empty (they will
87
+ be removed in Twig 3.0):
88
+
89
+ * ``Twig_CompilerInterface`` (use ``Twig_Compiler`` instead)
90
+ * ``Twig_LexerInterface`` (use ``Twig_Lexer`` instead)
91
+ * ``Twig_NodeInterface`` (use ``Twig_Node`` instead)
92
+ * ``Twig_ParserInterface`` (use ``Twig_Parser`` instead)
93
+ * ``Twig_ExistsLoaderInterface`` (merged with ``Twig_LoaderInterface``)
94
+ * ``Twig_TemplateInterface`` (use ``Twig_Template`` instead, and use
95
+ those constants Twig_Template::ANY_CALL, Twig_Template::ARRAY_CALL,
96
+ Twig_Template::METHOD_CALL)
97
+
98
+ Globals
99
+ -------
100
+
101
+ * As of Twig 2.x, the ability to register a global variable after the runtime
102
+ or the extensions have been initialized is not possible anymore (but
103
+ changing the value of an already registered global is possible).
vendor/vendor/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
vendor/vendor/twig/twig/doc/filters/batch.rst ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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. If you provide a second parameter, it is used to fill
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>
vendor/vendor/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' #}
vendor/vendor/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
+ * ``from``: The input charset
25
+ * ``to``: The output charset
26
+
27
+ .. _`iconv`: http://php.net/iconv
28
+ .. _`mbstring`: http://php.net/mbstring
vendor/vendor/twig/twig/doc/filters/date.rst ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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('core')->setDateFormat('d/m/Y', '%d days');
58
+
59
+ Timezone
60
+ --------
61
+
62
+ By default, the date is displayed by applying the default timezone (the one
63
+ specified in php.ini or declared in Twig -- see below), but you can override
64
+ it by explicitly specifying a timezone:
65
+
66
+ .. code-block:: jinja
67
+
68
+ {{ post.published_at|date("m/d/Y", "Europe/Paris") }}
69
+
70
+ If the date is already a DateTime object, and if you want to keep its current
71
+ timezone, pass ``false`` as the timezone value:
72
+
73
+ .. code-block:: jinja
74
+
75
+ {{ post.published_at|date("m/d/Y", false) }}
76
+
77
+ The default timezone can also be set globally by calling ``setTimezone()``:
78
+
79
+ .. code-block:: php
80
+
81
+ $twig = new Twig_Environment($loader);
82
+ $twig->getExtension('core')->setTimezone('Europe/Paris');
83
+
84
+ Arguments
85
+ ---------
86
+
87
+ * ``format``: The date format
88
+ * ``timezone``: The date timezone
89
+
90
+ .. _`strtotime`: http://www.php.net/strtotime
91
+ .. _`DateTime`: http://www.php.net/DateTime
92
+ .. _`DateInterval`: http://www.php.net/DateInterval
93
+ .. _`date`: http://www.php.net/date
94
+ .. _`DateInterval::format`: http://www.php.net/DateInterval.format
vendor/vendor/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
vendor/vendor/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
vendor/vendor/twig/twig/doc/filters/escape.rst ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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('core')->setEscaper('csv', 'csv_escaper'));
101
+
102
+ When called by Twig, the callable receives the Twig environment instance, the
103
+ string to escape, and the charset.
104
+
105
+ .. note::
106
+
107
+ Built-in escapers cannot be overridden mainly they should be considered as
108
+ the final implementation and also for better performance.
109
+
110
+ Arguments
111
+ ---------
112
+
113
+ * ``strategy``: The escaping strategy
114
+ * ``charset``: The string charset
115
+
116
+ .. _`htmlspecialchars`: http://php.net/htmlspecialchars
vendor/vendor/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
vendor/vendor/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>`
vendor/vendor/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
+ nl2br
24
+ number_format
25
+ merge
26
+ upper
27
+ raw
28
+ replace
29
+ reverse
30
+ round
31
+ slice
32
+ sort
33
+ split
34
+ striptags
35
+ title
36
+ trim
37
+ url_encode
vendor/vendor/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
vendor/vendor/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 string:
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
vendor/vendor/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 %}
vendor/vendor/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
vendor/vendor/twig/twig/doc/filters/length.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``length``
2
+ ==========
3
+
4
+ The ``length`` filters 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 %}
vendor/vendor/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' #}
vendor/vendor/twig/twig/doc/filters/merge.rst ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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' } #}
vendor/vendor/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.
vendor/vendor/twig/twig/doc/filters/number_format.rst ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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('core')->setNumberFormat(3, '.', ',');
34
+
35
+ The defaults set for ``number_format`` can be over-ridden upon each call using the
36
+ additional parameters.
37
+
38
+ Arguments
39
+ ---------
40
+
41
+ * ``decimal``: The number of decimal points to display
42
+ * ``decimal_point``: The character(s) to use for the decimal point
43
+ * ``thousand_sep``: The character(s) to use for the thousands separator
44
+
45
+ .. _`number_format`: http://php.net/number_format
vendor/vendor/twig/twig/doc/filters/raw.rst ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
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 %}
vendor/vendor/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
+ * ``replace_pairs``: The placeholder values
18
+
19
+ .. seealso:: :doc:`format<format>`
vendor/vendor/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
vendor/vendor/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
vendor/vendor/twig/twig/doc/filters/slice.rst ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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] }}
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
+ `substr`_ for strings.
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
+ .. _`substr`: http://php.net/substr
vendor/vendor/twig/twig/doc/filters/sort.rst ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.
16
+
17
+ .. _`asort`: http://php.net/asort
vendor/vendor/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
+ {{ "one,two,three"|split(',') }}
13
+ {# returns ['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
+ {{ "one,two,three,four,five"|split(',', 3) }}
28
+ {# returns ['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
+ {{ "123"|split('') }}
36
+ {# returns ['1', '2', '3'] #}
37
+
38
+ {{ "aabbcc"|split('', 2) }}
39
+ {# returns ['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
vendor/vendor/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
vendor/vendor/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' #}
vendor/vendor/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
vendor/vendor/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' #}
vendor/vendor/twig/twig/doc/filters/url_encode.rst ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ The ``url_encode`` filter percent encodes a given string as URL segment
8
+ or an array as query string:
9
+
10
+ .. code-block:: jinja
11
+
12
+ {{ "path-seg*ment"|url_encode }}
13
+ {# outputs "path-seg%2Ament" #}
14
+
15
+ {{ "string with spaces"|url_encode(true) }}
16
+ {# outputs "string%20with%20spaces" #}
17
+
18
+ {{ {'param': 'value', 'foo': 'bar'}|url_encode }}
19
+ {# outputs "param=value&foo=bar" #}
20
+
21
+ .. note::
22
+
23
+ Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass
24
+ ``true`` as the first parameter) or the `http_build_query`_ function.
25
+
26
+ .. _`urlencode`: http://php.net/urlencode
27
+ .. _`rawurlencode`: http://php.net/rawurlencode
28
+ .. _`http_build_query`: http://php.net/http_build_query
vendor/vendor/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.
vendor/vendor/twig/twig/doc/functions/block.rst ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``block``
2
+ =========
3
+
4
+ When a template uses inheritance and if you want to print a block multiple
5
+ times, use the ``block`` function:
6
+
7
+ .. code-block:: jinja
8
+
9
+ <title>{% block title %}{% endblock %}</title>
10
+
11
+ <h1>{{ block('title') }}</h1>
12
+
13
+ {% block body %}{% endblock %}
14
+
15
+ .. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>`
vendor/vendor/twig/twig/doc/functions/constant.rst ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``constant``
2
+ ============
3
+
4
+ .. versionadded: 1.12.1
5
+ constant now accepts object instances as the second argument.
6
+
7
+ ``constant`` returns the constant value for a given string:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ some_date|date(constant('DATE_W3C')) }}
12
+ {{ constant('Namespace\\Classname::CONSTANT_NAME') }}
13
+
14
+ As of 1.12.1 you can read constants from object instances as well:
15
+
16
+ .. code-block:: jinja
17
+
18
+ {{ constant('RSS', date) }}
vendor/vendor/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
vendor/vendor/twig/twig/doc/functions/date.rst ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 a format supported by the `date`_ function.
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('core')->setTimezone('Europe/Paris');
45
+
46
+ Arguments
47
+ ---------
48
+
49
+ * ``date``: The date
50
+ * ``timezone``: The timezone
51
+
52
+ .. _`date`: http://www.php.net/date
vendor/vendor/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
vendor/vendor/twig/twig/doc/functions/include.rst ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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`` object, Twig will use it
41
+ directly::
42
+
43
+ // {{ include(template) }}
44
+
45
+ $template = $twig->loadTemplate('some_template.twig');
46
+
47
+ $twig->loadTemplate('template.twig')->display(array('template' => $template));
48
+
49
+ When you set the ``ignore_missing`` flag, Twig will return an empty string if
50
+ the template does not exist:
51
+
52
+ .. code-block:: jinja
53
+
54
+ {{ include('sidebar.html', ignore_missing = true) }}
55
+
56
+ You can also provide a list of templates that are checked for existence before
57
+ inclusion. The first template that exists will be rendered:
58
+
59
+ .. code-block:: jinja
60
+
61
+ {{ include(['page_detailed.html', 'page.html']) }}
62
+
63
+ If ``ignore_missing`` is set, it will fall back to rendering nothing if none
64
+ of the templates exist, otherwise it will throw an exception.
65
+
66
+ When including a template created by an end user, you should consider
67
+ sandboxing it:
68
+
69
+ .. code-block:: jinja
70
+
71
+ {{ include('page.html', sandboxed = true) }}
72
+
73
+ Arguments
74
+ ---------
75
+
76
+ * ``template``: The template to render
77
+ * ``variables``: The variables to pass to the template
78
+ * ``with_context``: Whether to pass the current context variables or not
79
+ * ``ignore_missing``: Whether to ignore missing templates or not
80
+ * ``sandboxed``: Whether to sandbox the template or not
vendor/vendor/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
vendor/vendor/twig/twig/doc/functions/max.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: "two", 1: "one", 3: "three", 5: "five", 4: "for"}) }}
19
+ {# return "two" #}
vendor/vendor/twig/twig/doc/functions/min.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: "two", 1: "one", 3: "three", 5: "five", 4: "for"}) }}
19
+ {# return "five" #}
vendor/vendor/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>`
vendor/vendor/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
vendor/vendor/twig/twig/doc/functions/range.rst ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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):
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
+ The Twig built-in ``..`` operator is just syntactic sugar for the ``range``
26
+ function (with a step of 1):
27
+
28
+ .. code-block:: jinja
29
+
30
+ {% for i in 0..3 %}
31
+ {{ i }},
32
+ {% endfor %}
33
+
34
+ .. tip::
35
+
36
+ The ``range`` function works as the native PHP `range`_ function.
37
+
38
+ Arguments
39
+ ---------
40
+
41
+ * ``low``: The first value of the sequence.
42
+ * ``high``: The highest possible value of the sequence.
43
+ * ``step``: The increment between elements of the sequence.
44
+
45
+ .. _`range`: http://php.net/range
vendor/vendor/twig/twig/doc/functions/source.rst ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ``source``
2
+ ==========
3
+
4
+ .. versionadded:: 1.15
5
+ The source function was added in Twig 1.15.
6
+
7
+ The ``source`` function returns the content of a template without rendering it:
8
+
9
+ .. code-block:: jinja
10
+
11
+ {{ source('template.html') }}
12
+ {{ source(some_var) }}
13
+
14
+ The function uses the same template loaders as the ones used to include
15
+ templates. So, if you are using the filesystem loader, the templates are looked
16
+ for in the paths defined by it.
17
+
18
+ Arguments
19
+ ---------
20
+
21
+ * ``name``: The name of the template to read
vendor/vendor/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
vendor/vendor/twig/twig/doc/index.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Twig
2
+ ====
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+
7
+ intro
8
+ templates
9
+ api
10
+ advanced
11
+ internals
12
+ recipes
13
+ coding_standards
14
+ tags/index
15
+ filters/index
16
+ functions/index
17
+ tests/index
18
+ installation
19
+ deprecated
vendor/vendor/twig/twig/doc/installation.rst ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ 1. Install Composer in your project:
13
+
14
+ .. code-block:: bash
15
+
16
+ curl -s http://getcomposer.org/installer | php
17
+
18
+ 2. Create a ``composer.json`` file in your project root:
19
+
20
+ .. code-block:: javascript
21
+
22
+ {
23
+ "require": {
24
+ "twig/twig": "1.*"
25
+ }
26
+ }
27
+
28
+ 3. Install via Composer
29
+
30
+ .. code-block:: bash
31
+
32
+ php composer.phar install
33
+
34
+ .. note::
35
+ If you want to learn more about Composer, the ``composer.json`` file syntax
36
+ and its usage, you can read the `online documentation`_.
37
+
38
+ Installing from the tarball release
39
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40
+
41
+ 1. Download the most recent tarball from the `download page`_
42
+ 2. Unpack the tarball
43
+ 3. Move the files somewhere in your project
44
+
45
+ Installing the development version
46
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47
+
48
+ 1. Install Git
49
+ 2. ``git clone git://github.com/fabpot/Twig.git``
50
+
51
+ Installing the PEAR package
52
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
53
+
54
+ 1. Install PEAR
55
+ 2. ``pear channel-discover pear.twig-project.org``
56
+ 3. ``pear install twig/Twig`` (or ``pear install twig/Twig-beta``)
57
+
58
+ Installing the C extension
59
+ --------------------------
60
+
61
+ .. versionadded:: 1.4
62
+ The C extension was added in Twig 1.4.
63
+
64
+ Twig comes with a C extension that enhances the performance of the Twig
65
+ runtime engine.
66
+
67
+ You can install it via PEAR:
68
+
69
+ 1. Install PEAR
70
+ 2. ``pear channel-discover pear.twig-project.org``
71
+ 3. ``pear install twig/CTwig`` (or ``pear install twig/CTwig-beta``)
72
+
73
+ Or manually like any other PHP extension:
74
+
75
+ .. code-block:: bash
76
+
77
+ $ cd ext/twig
78
+ $ phpize
79
+ $ ./configure
80
+ $ make
81
+ $ make install
82
+
83
+ For Windows:
84
+
85
+ 1. Setup the build environment following the `PHP documentation`_
86
+ 2. Put Twig's C extension source code into ``C:\php-sdk\phpdev\vcXX\x86\php-source-directory\ext\twig``
87
+ 3. Use the ``configure --disable-all --enable-cli --enable-twig=shared`` command instead of step 14
88
+ 4. ``nmake``
89
+ 5. Copy the ``C:\php-sdk\phpdev\vcXX\x86\php-source-directory\Release_TS\php_twig.dll`` file to your PHP setup.
90
+
91
+ .. tip::
92
+
93
+ For Windows ZendServer, TS is not enabled as mentionned in `Zend Server
94
+ FAQ`_.
95
+
96
+ You have to use `configure --disable-all --disable-zts --enable-cli
97
+ --enable-twig=shared` to be able to build the twig C extension for
98
+ ZendServer.
99
+
100
+ The built DLL will be available in
101
+ C:\\php-sdk\\phpdev\\vcXX\\x86\\php-source-directory\\Release
102
+
103
+ Finally, enable the extension in your ``php.ini`` configuration file:
104
+
105
+ .. code-block:: ini
106
+
107
+ extension=twig.so #For Unix systems
108
+ extension=php_twig.dll #For Windows systems
109
+
110
+ And from now on, Twig will automatically compile your templates to take
111
+ advantage of the C extension. Note that this extension does not replace the
112
+ PHP code but only provides an optimized version of the
113
+ ``Twig_Template::getAttribute()`` method.
114
+
115
+ .. _`download page`: https://github.com/fabpot/Twig/tags
116
+ .. _`online documentation`: http://getcomposer.org/doc
117
+ .. _`PHP documentation`: https://wiki.php.net/internals/windows/stepbystepbuild
118
+ .. _`Zend Server FAQ`: http://www.zend.com/en/products/server/faq#faqD6
vendor/vendor/twig/twig/doc/internals.rst ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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($source, $identifier);
48
+
49
+ As the stream has a ``__toString()`` method, you can have a textual
50
+ representation of it by echoing the object::
51
+
52
+ echo $stream."\n";
53
+
54
+ Here is the output for the ``Hello {{ name }}`` template:
55
+
56
+ .. code-block:: text
57
+
58
+ TEXT_TYPE(Hello )
59
+ VAR_START_TYPE()
60
+ NAME_TYPE(name)
61
+ VAR_END_TYPE()
62
+ EOF_TYPE()
63
+
64
+ .. note::
65
+
66
+ The default lexer (``Twig_Lexer``) can be changed by calling
67
+ the ``setLexer()`` method::
68
+
69
+ $twig->setLexer($lexer);
70
+
71
+ The Parser
72
+ ----------
73
+
74
+ The parser converts the token stream into an AST (Abstract Syntax Tree), or a
75
+ node tree (an instance of ``Twig_Node_Module``). The core extension defines
76
+ the basic nodes like: ``for``, ``if``, ... and the expression nodes.
77
+
78
+ You can manually convert a token stream into a node tree by calling the
79
+ ``parse()`` method of an environment::
80
+
81
+ $nodes = $twig->parse($stream);
82
+
83
+ Echoing the node object gives you a nice representation of the tree::
84
+
85
+ echo $nodes."\n";
86
+
87
+ Here is the output for the ``Hello {{ name }}`` template:
88
+
89
+ .. code-block:: text
90
+
91
+ Twig_Node_Module(
92
+ Twig_Node_Text(Hello )
93
+ Twig_Node_Print(
94
+ Twig_Node_Expression_Name(name)
95
+ )
96
+ )
97
+
98
+ .. note::
99
+
100
+ The default parser (``Twig_TokenParser``) can be changed by calling the
101
+ ``setParser()`` method::
102
+
103
+ $twig->setParser($parser);
104
+
105
+ The Compiler
106
+ ------------
107
+
108
+ The last step is done by the compiler. It takes a node tree as an input and
109
+ generates PHP code usable for runtime execution of the template.
110
+
111
+ You can manually compile a node tree to PHP code with the ``compile()`` method
112
+ of an environment::
113
+
114
+ $php = $twig->compile($nodes);
115
+
116
+ The generated template for a ``Hello {{ name }}`` template reads as follows
117
+ (the actual output can differ depending on the version of Twig you are
118
+ using)::
119
+
120
+ /* Hello {{ name }} */
121
+ class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template
122
+ {
123
+ protected function doDisplay(array $context, array $blocks = array())
124
+ {
125
+ // line 1
126
+ echo "Hello ";
127
+ echo twig_escape_filter($this->env, $this->getContext($context, "name"), "ndex", null, true);
128
+ }
129
+
130
+ // some more code
131
+ }
132
+
133
+ .. note::
134
+
135
+ The default compiler (``Twig_Compiler``) can be changed by calling the
136
+ ``setCompiler()`` method::
137
+
138
+ $twig->setCompiler($compiler);
vendor/vendor/twig/twig/doc/intro.rst ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 its own custom tags and filters, and create its own DSL.
23
+
24
+ Prerequisites
25
+ -------------
26
+
27
+ Twig needs at least **PHP 5.2.4** to run.
28
+
29
+ Installation
30
+ ------------
31
+
32
+ The recommended way to install Twig is via Composer:
33
+
34
+ .. code-block:: bash
35
+
36
+ composer require twig/twig:1.*
37
+
38
+ .. note::
39
+
40
+ To learn more about the other installation methods, read the
41
+ :doc:`installation<installation>` chapter; it also explains how to install
42
+ the Twig C extension.
43
+
44
+ Basic API Usage
45
+ ---------------
46
+
47
+ This section gives you a brief introduction to the PHP API for Twig.
48
+
49
+ .. code-block:: php
50
+
51
+ require_once '/path/to/vendor/autoload.php';
52
+
53
+ $loader = new Twig_Loader_String();
54
+ $twig = new Twig_Environment($loader);
55
+
56
+ echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
57
+
58
+ Twig uses a loader (``Twig_Loader_String``) to locate templates, and an
59
+ environment (``Twig_Environment``) to store the configuration.
60
+
61
+ The ``render()`` method loads the template passed as a first argument and
62
+ renders it with the variables passed as a second argument.
63
+
64
+ As templates are generally stored on the filesystem, Twig also comes with a
65
+ filesystem loader::
66
+
67
+ $loader = new Twig_Loader_Filesystem('/path/to/templates');
68
+ $twig = new Twig_Environment($loader, array(
69
+ 'cache' => '/path/to/compilation_cache',
70
+ ));
71
+
72
+ echo $twig->render('index.html', array('name' => 'Fabien'));
73
+
74
+ .. tip::
75
+
76
+ If you are not using Composer, use the Twig built-in autoloader::
77
+
78
+ require_once '/path/to/lib/Twig/Autoloader.php';
79
+ Twig_Autoloader::register();
vendor/vendor/twig/twig/doc/recipes.rst ADDED
@@ -0,0 +1,475 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Recipes
2
+ =======
3
+
4
+ Making a Layout conditional
5
+ ---------------------------
6
+
7
+ Working with Ajax means that the same content is sometimes displayed as is,
8
+ and sometimes decorated with a layout. As Twig layout template names can be
9
+ any valid expression, you can pass a variable that evaluates to ``true`` when
10
+ the request is made via Ajax and choose the layout accordingly:
11
+
12
+ .. code-block:: jinja
13
+
14
+ {% extends request.ajax ? "base_ajax.html" : "base.html" %}
15
+
16
+ {% block content %}
17
+ This is the content to be displayed.
18
+ {% endblock %}
19
+
20
+ Making an Include dynamic
21
+ -------------------------
22
+
23
+ When including a template, its name does not need to be a string. For
24
+ instance, the name can depend on the value of a variable:
25
+
26
+ .. code-block:: jinja
27
+
28
+ {% include var ~ '_foo.html' %}
29
+
30
+ If ``var`` evaluates to ``index``, the ``index_foo.html`` template will be
31
+ rendered.
32
+
33
+ As a matter of fact, the template name can be any valid expression, such as
34
+ the following:
35
+
36
+ .. code-block:: jinja
37
+
38
+ {% include var|default('index') ~ '_foo.html' %}
39
+
40
+ Overriding a Template that also extends itself
41
+ ----------------------------------------------
42
+
43
+ A template can be customized in two different ways:
44
+
45
+ * *Inheritance*: A template *extends* a parent template and overrides some
46
+ blocks;
47
+
48
+ * *Replacement*: If you use the filesystem loader, Twig loads the first
49
+ template it finds in a list of configured directories; a template found in a
50
+ directory *replaces* another one from a directory further in the list.
51
+
52
+ But how do you combine both: *replace* a template that also extends itself
53
+ (aka a template in a directory further in the list)?
54
+
55
+ Let's say that your templates are loaded from both ``.../templates/mysite``
56
+ and ``.../templates/default`` in this order. The ``page.twig`` template,
57
+ stored in ``.../templates/default`` reads as follows:
58
+
59
+ .. code-block:: jinja
60
+
61
+ {# page.twig #}
62
+ {% extends "layout.twig" %}
63
+
64
+ {% block content %}
65
+ {% endblock %}
66
+
67
+ You can replace this template by putting a file with the same name in
68
+ ``.../templates/mysite``. And if you want to extend the original template, you
69
+ might be tempted to write the following:
70
+
71
+ .. code-block:: jinja
72
+
73
+ {# page.twig in .../templates/mysite #}
74
+ {% extends "page.twig" %} {# from .../templates/default #}
75
+
76
+ Of course, this will not work as Twig will always load the template from
77
+ ``.../templates/mysite``.
78
+
79
+ It turns out it is possible to get this to work, by adding a directory right
80
+ at the end of your template directories, which is the parent of all of the
81
+ other directories: ``.../templates`` in our case. This has the effect of
82
+ making every template file within our system uniquely addressable. Most of the
83
+ time you will use the "normal" paths, but in the special case of wanting to
84
+ extend a template with an overriding version of itself we can reference its
85
+ parent's full, unambiguous template path in the extends tag:
86
+
87
+ .. code-block:: jinja
88
+
89
+ {# page.twig in .../templates/mysite #}
90
+ {% extends "default/page.twig" %} {# from .../templates #}
91
+
92
+ .. note::
93
+
94
+ This recipe was inspired by the following Django wiki page:
95
+ http://code.djangoproject.com/wiki/ExtendingTemplates
96
+
97
+ Customizing the Syntax
98
+ ----------------------
99
+
100
+ Twig allows some syntax customization for the block delimiters. It's not
101
+ recommended to use this feature as templates will be tied with your custom
102
+ syntax. But for specific projects, it can make sense to change the defaults.
103
+
104
+ To change the block delimiters, you need to create your own lexer object::
105
+
106
+ $twig = new Twig_Environment();
107
+
108
+ $lexer = new Twig_Lexer($twig, array(
109
+ 'tag_comment' => array('{#', '#}'),
110
+ 'tag_block' => array('{%', '%}'),
111
+ 'tag_variable' => array('{{', '}}'),
112
+ 'interpolation' => array('#{', '}'),
113
+ ));
114
+ $twig->setLexer($lexer);
115
+
116
+ Here are some configuration example that simulates some other template engines
117
+ syntax::
118
+
119
+ // Ruby erb syntax
120
+ $lexer = new Twig_Lexer($twig, array(
121
+ 'tag_comment' => array('<%#', '%>'),
122
+ 'tag_block' => array('<%', '%>'),
123
+ 'tag_variable' => array('<%=', '%>'),
124
+ ));
125
+
126
+ // SGML Comment Syntax
127
+ $lexer = new Twig_Lexer($twig, array(
128
+ 'tag_comment' => array('<!--#', '-->'),
129
+ 'tag_block' => array('<!--', '-->'),
130
+ 'tag_variable' => array('${', '}'),
131
+ ));
132
+
133
+ // Smarty like
134
+ $lexer = new Twig_Lexer($twig, array(
135
+ 'tag_comment' => array('{*', '*}'),
136
+ 'tag_block' => array('{', '}'),
137
+ 'tag_variable' => array('{$', '}'),
138
+ ));
139
+
140
+ Using dynamic Object Properties
141
+ -------------------------------
142
+
143
+ When Twig encounters a variable like ``article.title``, it tries to find a
144
+ ``title`` public property in the ``article`` object.
145
+
146
+ It also works if the property does not exist but is rather defined dynamically
147
+ thanks to the magic ``__get()`` method; you just need to also implement the
148
+ ``__isset()`` magic method like shown in the following snippet of code::
149
+
150
+ class Article
151
+ {
152
+ public function __get($name)
153
+ {
154
+ if ('title' == $name) {
155
+ return 'The title';
156
+ }
157
+
158
+ // throw some kind of error
159
+ }
160
+
161
+ public function __isset($name)
162
+ {
163
+ if ('title' == $name) {
164
+ return true;
165
+ }
166
+
167
+ return false;
168
+ }
169
+ }
170
+
171
+ Accessing the parent Context in Nested Loops
172
+ --------------------------------------------
173
+
174
+ Sometimes, when using nested loops, you need to access the parent context. The
175
+ parent context is always accessible via the ``loop.parent`` variable. For
176
+ instance, if you have the following template data::
177
+
178
+ $data = array(
179
+ 'topics' => array(
180
+ 'topic1' => array('Message 1 of topic 1', 'Message 2 of topic 1'),
181
+ 'topic2' => array('Message 1 of topic 2', 'Message 2 of topic 2'),
182
+ ),
183
+ );
184
+
185
+ And the following template to display all messages in all topics:
186
+
187
+ .. code-block:: jinja
188
+
189
+ {% for topic, messages in topics %}
190
+ * {{ loop.index }}: {{ topic }}
191
+ {% for message in messages %}
192
+ - {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }}
193
+ {% endfor %}
194
+ {% endfor %}
195
+
196
+ The output will be similar to:
197
+
198
+ .. code-block:: text
199
+
200
+ * 1: topic1
201
+ - 1.1: The message 1 of topic 1
202
+ - 1.2: The message 2 of topic 1
203
+ * 2: topic2
204
+ - 2.1: The message 1 of topic 2
205
+ - 2.2: The message 2 of topic 2
206
+
207
+ In the inner loop, the ``loop.parent`` variable is used to access the outer
208
+ context. So, the index of the current ``topic`` defined in the outer for loop
209
+ is accessible via the ``loop.parent.loop.index`` variable.
210
+
211
+ Defining undefined Functions and Filters on the Fly
212
+ ---------------------------------------------------
213
+
214
+ When a function (or a filter) is not defined, Twig defaults to throw a
215
+ ``Twig_Error_Syntax`` exception. However, it can also call a `callback`_ (any
216
+ valid PHP callable) which should return a function (or a filter).
217
+
218
+ For filters, register callbacks with ``registerUndefinedFilterCallback()``.
219
+ For functions, use ``registerUndefinedFunctionCallback()``::
220
+
221
+ // auto-register all native PHP functions as Twig functions
222
+ // don't try this at home as it's not secure at all!
223
+ $twig->registerUndefinedFunctionCallback(function ($name) {
224
+ if (function_exists($name)) {
225
+ return new Twig_Function_Function($name);
226
+ }
227
+
228
+ return false;
229
+ });
230
+
231
+ If the callable is not able to return a valid function (or filter), it must
232
+ return ``false``.
233
+
234
+ If you register more than one callback, Twig will call them in turn until one
235
+ does not return ``false``.
236
+
237
+ .. tip::
238
+
239
+ As the resolution of functions and filters is done during compilation,
240
+ there is no overhead when registering these callbacks.
241
+
242
+ Validating the Template Syntax
243
+ ------------------------------
244
+
245
+ When template code is providing by a third-party (through a web interface for
246
+ instance), it might be interesting to validate the template syntax before
247
+ saving it. If the template code is stored in a `$template` variable, here is
248
+ how you can do it::
249
+
250
+ try {
251
+ $twig->parse($twig->tokenize($template));
252
+
253
+ // the $template is valid
254
+ } catch (Twig_Error_Syntax $e) {
255
+ // $template contains one or more syntax errors
256
+ }
257
+
258
+ If you iterate over a set of files, you can pass the filename to the
259
+ ``tokenize()`` method to get the filename in the exception message::
260
+
261
+ foreach ($files as $file) {
262
+ try {
263
+ $twig->parse($twig->tokenize($template, $file));
264
+
265
+ // the $template is valid
266
+ } catch (Twig_Error_Syntax $e) {
267
+ // $template contains one or more syntax errors
268
+ }
269
+ }
270
+
271
+ .. note::
272
+
273
+ This method won't catch any sandbox policy violations because the policy
274
+ is enforced during template rendering (as Twig needs the context for some
275
+ checks like allowed methods on objects).
276
+
277
+ Refreshing modified Templates when APC is enabled and apc.stat = 0
278
+ ------------------------------------------------------------------
279
+
280
+ When using APC with ``apc.stat`` set to ``0`` and Twig cache enabled, clearing
281
+ the template cache won't update the APC cache. To get around this, one can
282
+ extend ``Twig_Environment`` and force the update of the APC cache when Twig
283
+ rewrites the cache::
284
+
285
+ class Twig_Environment_APC extends Twig_Environment
286
+ {
287
+ protected function writeCacheFile($file, $content)
288
+ {
289
+ parent::writeCacheFile($file, $content);
290
+
291
+ // Compile cached file into bytecode cache
292
+ apc_compile_file($file);
293
+ }
294
+ }
295
+
296
+ Reusing a stateful Node Visitor
297
+ -------------------------------
298
+
299
+ When attaching a visitor to a ``Twig_Environment`` instance, Twig uses it to
300
+ visit *all* templates it compiles. If you need to keep some state information
301
+ around, you probably want to reset it when visiting a new template.
302
+
303
+ This can be easily achieved with the following code::
304
+
305
+ protected $someTemplateState = array();
306
+
307
+ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
308
+ {
309
+ if ($node instanceof Twig_Node_Module) {
310
+ // reset the state as we are entering a new template
311
+ $this->someTemplateState = array();
312
+ }
313
+
314
+ // ...
315
+
316
+ return $node;
317
+ }
318
+
319
+ Using the Template name to set the default Escaping Strategy
320
+ ------------------------------------------------------------
321
+
322
+ .. versionadded:: 1.8
323
+ This recipe requires Twig 1.8 or later.
324
+
325
+ The ``autoescape`` option determines the default escaping strategy to use when
326
+ no escaping is applied on a variable. When Twig is used to mostly generate
327
+ HTML files, you can set it to ``html`` and explicitly change it to ``js`` when
328
+ you have some dynamic JavaScript files thanks to the ``autoescape`` tag:
329
+
330
+ .. code-block:: jinja
331
+
332
+ {% autoescape 'js' %}
333
+ ... some JS ...
334
+ {% endautoescape %}
335
+
336
+ But if you have many HTML and JS files, and if your template names follow some
337
+ conventions, you can instead determine the default escaping strategy to use
338
+ based on the template name. Let's say that your template names always end
339
+ with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for
340
+ stylesheets, here is how you can configure Twig::
341
+
342
+ class TwigEscapingGuesser
343
+ {
344
+ function guess($filename)
345
+ {
346
+ // get the format
347
+ $format = substr($filename, strrpos($filename, '.') + 1);
348
+
349
+ switch ($format) {
350
+ case 'js':
351
+ return 'js';
352
+ case 'css':
353
+ return 'css';
354
+ case 'html':
355
+ default:
356
+ return 'html';
357
+ }
358
+ }
359
+ }
360
+
361
+ $loader = new Twig_Loader_Filesystem('/path/to/templates');
362
+ $twig = new Twig_Environment($loader, array(
363
+ 'autoescape' => array(new TwigEscapingGuesser(), 'guess'),
364
+ ));
365
+
366
+ This dynamic strategy does not incur any overhead at runtime as auto-escaping
367
+ is done at compilation time.
368
+
369
+ Using a Database to store Templates
370
+ -----------------------------------
371
+
372
+ If you are developing a CMS, templates are usually stored in a database. This
373
+ recipe gives you a simple PDO template loader you can use as a starting point
374
+ for your own.
375
+
376
+ First, let's create a temporary in-memory SQLite3 database to work with::
377
+
378
+ $dbh = new PDO('sqlite::memory:');
379
+ $dbh->exec('CREATE TABLE templates (name STRING, source STRING, last_modified INTEGER)');
380
+ $base = '{% block content %}{% endblock %}';
381
+ $index = '
382
+ {% extends "base.twig" %}
383
+ {% block content %}Hello {{ name }}{% endblock %}
384
+ ';
385
+ $now = time();
386
+ $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('base.twig', '$base', $now)");
387
+ $dbh->exec("INSERT INTO templates (name, source, last_modified) VALUES ('index.twig', '$index', $now)");
388
+
389
+ We have created a simple ``templates`` table that hosts two templates:
390
+ ``base.twig`` and ``index.twig``.
391
+
392
+ Now, let's define a loader able to use this database::
393
+
394
+ class DatabaseTwigLoader implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
395
+ {
396
+ protected $dbh;
397
+
398
+ public function __construct(PDO $dbh)
399
+ {
400
+ $this->dbh = $dbh;
401
+ }
402
+
403
+ public function getSource($name)
404
+ {
405
+ if (false === $source = $this->getValue('source', $name)) {
406
+ throw new Twig_Error_Loader(sprintf('Template "%s" does not exist.', $name));
407
+ }
408
+
409
+ return $source;
410
+ }
411
+
412
+ // Twig_ExistsLoaderInterface as of Twig 1.11
413
+ public function exists($name)
414
+ {
415
+ return $name === $this->getValue('name', $name);
416
+ }
417
+
418
+ public function getCacheKey($name)
419
+ {
420
+ return $name;
421
+ }
422
+
423
+ public function isFresh($name, $time)
424
+ {
425
+ if (false === $lastModified = $this->getValue('last_modified', $name)) {
426
+ return false;
427
+ }
428
+
429
+ return $lastModified <= $time;
430
+ }
431
+
432
+ protected function getValue($column, $name)
433
+ {
434
+ $sth = $this->dbh->prepare('SELECT '.$column.' FROM templates WHERE name = :name');
435
+ $sth->execute(array(':name' => (string) $name));
436
+
437
+ return $sth->fetchColumn();
438
+ }
439
+ }
440
+
441
+ Finally, here is an example on how you can use it::
442
+
443
+ $loader = new DatabaseTwigLoader($dbh);
444
+ $twig = new Twig_Environment($loader);
445
+
446
+ echo $twig->render('index.twig', array('name' => 'Fabien'));
447
+
448
+ Using different Template Sources
449
+ --------------------------------
450
+
451
+ This recipe is the continuation of the previous one. Even if you store the
452
+ contributed templates in a database, you might want to keep the original/base
453
+ templates on the filesystem. When templates can be loaded from different
454
+ sources, you need to use the ``Twig_Loader_Chain`` loader.
455
+
456
+ As you can see in the previous recipe, we reference the template in the exact
457
+ same way as we would have done it with a regular filesystem loader. This is
458
+ the key to be able to mix and match templates coming from the database, the
459
+ filesystem, or any other loader for that matter: the template name should be a
460
+ logical name, and not the path from the filesystem::
461
+
462
+ $loader1 = new DatabaseTwigLoader($dbh);
463
+ $loader2 = new Twig_Loader_Array(array(
464
+ 'base.twig' => '{% block content %}{% endblock %}',
465
+ ));
466
+ $loader = new Twig_Loader_Chain(array($loader1, $loader2));
467
+
468
+ $twig = new Twig_Environment($loader);
469
+
470
+ echo $twig->render('index.twig', array('name' => 'Fabien'));
471
+
472
+ Now that the ``base.twig`` templates is defined in an array loader, you can
473
+ remove it from the database, and everything else will still work as before.
474
+
475
+ .. _callback: http://www.php.net/manual/en/function.is-callable.php
vendor/vendor/twig/twig/doc/tags/autoescape.rst ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ {# The following syntax works as of Twig 1.8 -- see the note below for previous versions #}
10
+
11
+ {% autoescape %}
12
+ Everything will be automatically escaped in this block
13
+ using the HTML strategy
14
+ {% endautoescape %}
15
+
16
+ {% autoescape 'html' %}
17
+ Everything will be automatically escaped in this block
18
+ using the HTML strategy
19
+ {% endautoescape %}
20
+
21
+ {% autoescape 'js' %}
22
+ Everything will be automatically escaped in this block
23
+ using the js escaping strategy
24
+ {% endautoescape %}
25
+
26
+ {% autoescape false %}
27
+ Everything will be outputted as is in this block
28
+ {% endautoescape %}
29
+
30
+ .. note::
31
+
32
+ Before Twig 1.8, the syntax was different:
33
+
34
+ .. code-block:: jinja
35
+
36
+ {% autoescape true %}
37
+ Everything will be automatically escaped in this block
38
+ using the HTML strategy
39
+ {% endautoescape %}
40
+
41
+ {% autoescape false %}
42
+ Everything will be outputted as is in this block
43
+ {% endautoescape %}
44
+
45
+ {% autoescape true js %}
46
+ Everything will be automatically escaped in this block
47
+ using the js escaping strategy
48
+ {% endautoescape %}
49
+
50
+ When automatic escaping is enabled everything is escaped by default except for
51
+ values explicitly marked as safe. Those can be marked in the template by using
52
+ the :doc:`raw<../filters/raw>` filter:
53
+
54
+ .. code-block:: jinja
55
+
56
+ {% autoescape %}
57
+ {{ safe_value|raw }}
58
+ {% endautoescape %}
59
+
60
+ Functions returning template data (like :doc:`macros<macro>` and
61
+ :doc:`parent<../functions/parent>`) always return safe markup.
62
+
63
+ .. note::
64
+
65
+ Twig is smart enough to not escape an already escaped value by the
66
+ :doc:`escape<../filters/escape>` filter.
67
+
68
+ .. note::
69
+
70
+ The chapter :doc:`Twig for Developers<../api>` gives more information
71
+ about when and how automatic escaping is applied.
vendor/vendor/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>`
vendor/vendor/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 %}
vendor/vendor/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 "filename" won't work as expected if you change the
174
+ context (for instance, if you embed a CSS/JavaScript template into an HTML
175
+ one). In that case, explicitly set the default auto-escaping strategy with
176
+ the ``autoescape`` tag.
177
+
178
+ .. seealso:: :doc:`include<../tags/include>`
vendor/vendor/twig/twig/doc/tags/extends.rst ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 few content, it's possible to use a shortcut syntax. The
135
+ following constructs do the same:
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`` object, Twig will use it as
157
+ the parent template::
158
+
159
+ // {% extends layout %}
160
+
161
+ $layout = $twig->loadTemplate('some_layout_template.twig');
162
+
163
+ $twig->display('template.twig', array('layout' => $layout));
164
+
165
+ .. versionadded:: 1.2
166
+ The possibility to pass an array of templates has been added in Twig 1.2.
167
+
168
+ You can also provide a list of templates that are checked for existence. The
169
+ first template that exists will be used as a parent:
170
+
171
+ .. code-block:: jinja
172
+
173
+ {% extends ['layout.html', 'base_layout.html'] %}
174
+
175
+ Conditional Inheritance
176
+ -----------------------
177
+
178
+ As the template name for the parent can be any valid Twig expression, it's
179
+ possible to make the inheritance mechanism conditional:
180
+
181
+ .. code-block:: jinja
182
+
183
+ {% extends standalone ? "minimum.html" : "base.html" %}
184
+
185
+ In this example, the template will extend the "minimum.html" layout template
186
+ if the ``standalone`` variable evaluates to ``true``, and "base.html"
187
+ otherwise.
188
+
189
+ How blocks work?
190
+ ----------------
191
+
192
+ A block provides a way to change how a certain part of a template is rendered
193
+ but it does not interfere in any way with the logic around it.
194
+
195
+ Let's take the following example to illustrate how a block works and more
196
+ importantly, how it does not work:
197
+
198
+ .. code-block:: jinja
199
+
200
+ {# base.twig #}
201
+
202
+ {% for post in posts %}
203
+ {% block post %}
204
+ <h1>{{ post.title }}</h1>
205
+ <p>{{ post.body }}</p>
206
+ {% endblock %}
207
+ {% endfor %}
208
+
209
+ If you render this template, the result would be exactly the same with or
210
+ without the ``block`` tag. The ``block`` inside the ``for`` loop is just a way
211
+ to make it overridable by a child template:
212
+
213
+ .. code-block:: jinja
214
+
215
+ {# child.twig #}
216
+
217
+ {% extends "base.twig" %}
218
+
219
+ {% block post %}
220
+ <article>
221
+ <header>{{ post.title }}</header>
222
+ <section>{{ post.text }}</section>
223
+ </article>
224
+ {% endblock %}
225
+
226
+ Now, when rendering the child template, the loop is going to use the block
227
+ defined in the child template instead of the one defined in the base one; the
228
+ executed template is then equivalent to the following one:
229
+
230
+ .. code-block:: jinja
231
+
232
+ {% for post in posts %}
233
+ <article>
234
+ <header>{{ post.title }}</header>
235
+ <section>{{ post.text }}</section>
236
+ </article>
237
+ {% endfor %}
238
+
239
+ Let's take another example: a block included within an ``if`` statement:
240
+
241
+ .. code-block:: jinja
242
+
243
+ {% if posts is empty %}
244
+ {% block head %}
245
+ {{ parent() }}
246
+
247
+ <meta name="robots" content="noindex, follow">
248
+ {% endblock head %}
249
+ {% endif %}
250
+
251
+ Contrary to what you might think, this template does not define a block
252
+ conditionally; it just makes overridable by a child template the output of
253
+ what will be rendered when the condition is ``true``.
254
+
255
+ If you want the output to be displayed conditionally, use the following
256
+ instead:
257
+
258
+ .. code-block:: jinja
259
+
260
+ {% block head %}
261
+ {{ parent() }}
262
+
263
+ {% if posts is empty %}
264
+ <meta name="robots" content="noindex, follow">
265
+ {% endif %}
266
+ {% endblock head %}
267
+
268
+ .. seealso:: :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`
vendor/vendor/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;" #}
vendor/vendor/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
vendor/vendor/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>
vendor/vendor/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>`
vendor/vendor/twig/twig/doc/tags/if.rst ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can use
33
+ more complex ``expressions`` there too:
34
+
35
+ .. code-block:: jinja
36
+
37
+ {% if kenny.sick %}
38
+ Kenny is sick.
39
+ {% elseif kenny.dead %}
40
+ You killed Kenny! You bastard!!!
41
+ {% else %}
42
+ Kenny looks okay --- so far
43
+ {% endif %}
vendor/vendor/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>`
vendor/vendor/twig/twig/doc/tags/include.rst ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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`` object, Twig will use it
54
+ directly::
55
+
56
+ // {% include template %}
57
+
58
+ $template = $twig->loadTemplate('some_template.twig');
59
+
60
+ $twig->loadTemplate('template.twig')->display(array('template' => $template));
61
+
62
+ .. versionadded:: 1.2
63
+ The ``ignore missing`` feature has been added in Twig 1.2.
64
+
65
+ You can mark an include with ``ignore missing`` in which case Twig will ignore
66
+ the statement if the template to be included does not exist. It has to be
67
+ placed just after the template name. Here some valid examples:
68
+
69
+ .. code-block:: jinja
70
+
71
+ {% include 'sidebar.html' ignore missing %}
72
+ {% include 'sidebar.html' ignore missing with {'foo': 'bar'} %}
73
+ {% include 'sidebar.html' ignore missing only %}
74
+
75
+ .. versionadded:: 1.2
76
+ The possibility to pass an array of templates has been added in Twig 1.2.
77
+
78
+ You can also provide a list of templates that are checked for existence before
79
+ inclusion. The first template that exists will be included:
80
+
81
+ .. code-block:: jinja
82
+
83
+ {% include ['page_detailed.html', 'page.html'] %}
84
+
85
+ If ``ignore missing`` is given, it will fall back to rendering nothing if none
86
+ of the templates exist, otherwise it will throw an exception.
vendor/vendor/twig/twig/doc/tags/index.rst ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Tags
2
+ ====
3
+
4
+ .. toctree::
5
+ :maxdepth: 1
6
+
7
+ autoescape
8
+ block
9
+ filter
10
+ do
11
+ embed
12
+ extends
13
+ flush
14
+ for
15
+ from
16
+ if
17
+ import
18
+ include
19
+ macro
20
+ sandbox
21
+ set
22
+ spaceless
23
+ use
24
+ verbatim
vendor/vendor/twig/twig/doc/tags/macro.rst ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 differs 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
+ But as with PHP functions, macros don't have access to the current template
24
+ variables.
25
+
26
+ .. tip::
27
+
28
+ You can pass the whole context as an argument by using the special
29
+ ``_context`` variable.
30
+
31
+ Macros can be defined in any template, and need to be "imported" before being
32
+ used (see the documentation for the :doc:`import<../tags/import>` tag for more
33
+ information):
34
+
35
+ .. code-block:: jinja
36
+
37
+ {% import "forms.html" as forms %}
38
+
39
+ The above ``import`` call imports the "forms.html" file (which can contain only
40
+ macros, or a template and some macros), and import the functions as items of
41
+ the ``forms`` variable.
42
+
43
+ The macro can then be called at will:
44
+
45
+ .. code-block:: jinja
46
+
47
+ <p>{{ forms.input('username') }}</p>
48
+ <p>{{ forms.input('password', null, 'password') }}</p>
49
+
50
+ If macros are defined and used in the same template, you can use the
51
+ special ``_self`` variable to import them:
52
+
53
+ .. code-block:: jinja
54
+
55
+ {% import _self as forms %}
56
+
57
+ <p>{{ forms.input('username') }}</p>
58
+
59
+ .. warning::
60
+
61
+ When you define a macro in the template where you are going to use it, you
62
+ might be tempted to call the macro directly via ``_self.input()`` instead
63
+ of importing it; even if seems to work, this is just a side-effect of the
64
+ current implementation and it won't work anymore in Twig 2.x.
65
+
66
+ When you want to use a macro in another macro from the same file, you need to
67
+ import it locally:
68
+
69
+ .. code-block:: jinja
70
+
71
+ {% macro input(name, value, type, size) %}
72
+ <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
73
+ {% endmacro %}
74
+
75
+ {% macro wrapped_input(name, value, type, size) %}
76
+ {% import _self as forms %}
77
+
78
+ <div class="field">
79
+ {{ forms.input(name, value, type, size) }}
80
+ </div>
81
+ {% endmacro %}
82
+
83
+ .. seealso:: :doc:`from<../tags/from>`, :doc:`import<../tags/import>`
vendor/vendor/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 %}
vendor/vendor/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 #}
vendor/vendor/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
+ :doc:`dedicated<../templates>` section of the documentation and learn how
37
+ you can also use the whitespace control modifier on your tags.
vendor/vendor/twig/twig/doc/tags/use.rst ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 Twig's feature 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
+ {% block sidebar %}{% endblock %}
44
+
45
+ In this example, the ``use`` statement imports the ``sidebar`` block into the
46
+ main template. The code is mostly equivalent to the following one (the
47
+ imported blocks are not outputted automatically):
48
+
49
+ .. code-block:: jinja
50
+
51
+ {% extends "base.html" %}
52
+
53
+ {% block sidebar %}{% endblock %}
54
+ {% block title %}{% endblock %}
55
+ {% block content %}{% endblock %}
56
+
57
+ .. note::
58
+
59
+ The ``use`` tag only imports a template if it does not extend another
60
+ template, if it does not define macros, and if the body is empty. But it
61
+ can *use* other templates.
62
+
63
+ .. note::
64
+
65
+ Because ``use`` statements are resolved independently of the context
66
+ passed to the template, the template reference cannot be an expression.
67
+
68
+ The main template can also override any imported block. If the template
69
+ already defines the ``sidebar`` block, then the one defined in ``blocks.html``
70
+ is ignored. To avoid name conflicts, you can rename imported blocks:
71
+
72
+ .. code-block:: jinja
73
+
74
+ {% extends "base.html" %}
75
+
76
+ {% use "blocks.html" with sidebar as base_sidebar %}
77
+
78
+ {% block sidebar %}{% endblock %}
79
+ {% block title %}{% endblock %}
80
+ {% block content %}{% endblock %}
81
+
82
+ .. versionadded:: 1.3
83
+ The ``parent()`` support was added in Twig 1.3.
84
+
85
+ The ``parent()`` function automatically determines the correct inheritance
86
+ tree, so it can be used when overriding a block defined in an imported
87
+ template:
88
+
89
+ .. code-block:: jinja
90
+
91
+ {% extends "base.html" %}
92
+
93
+ {% use "blocks.html" %}
94
+
95
+ {% block sidebar %}
96
+ {{ parent() }}
97
+ {% endblock %}
98
+
99
+ {% block title %}{% endblock %}
100
+ {% block content %}{% endblock %}
101
+
102
+ In this example, ``parent()`` will correctly call the ``sidebar`` block from
103
+ the ``blocks.html`` template.
104
+
105
+ .. tip::
106
+
107
+ In Twig 1.2, renaming allows you to simulate inheritance by calling the
108
+ "parent" block:
109
+
110
+ .. code-block:: jinja
111
+
112
+ {% extends "base.html" %}
113
+
114
+ {% use "blocks.html" with sidebar as parent_sidebar %}
115
+
116
+ {% block sidebar %}
117
+ {{ block('parent_sidebar') }}
118
+ {% endblock %}
119
+
120
+ .. note::
121
+
122
+ You can use as many ``use`` statements as you want in any given template.
123
+ If two imported templates define the same block, the latest one wins.
vendor/vendor/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.
vendor/vendor/twig/twig/doc/templates.rst ADDED
@@ -0,0 +1,873 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 the
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
+
62
+ Variables
63
+ ---------
64
+
65
+ The application passes variables to the templates you can mess around in the
66
+ template. Variables may have attributes or elements on them you can access
67
+ too. How a variable looks like heavily depends on the application providing
68
+ those.
69
+
70
+ You can use a dot (``.``) to access attributes of a variable (methods or
71
+ properties of a PHP object, or items of a PHP array), or the so-called
72
+ "subscript" syntax (``[]``):
73
+
74
+ .. code-block:: jinja
75
+
76
+ {{ foo.bar }}
77
+ {{ foo['bar'] }}
78
+
79
+ When the attribute contains special characters (like ``-`` that would be
80
+ interpreted as the minus operator), use the ``attribute`` function instead to
81
+ access the variable attribute:
82
+
83
+ .. code-block:: jinja
84
+
85
+ {# equivalent to the non-working foo.data-foo #}
86
+ {{ attribute(foo, 'data-foo') }}
87
+
88
+ .. note::
89
+
90
+ It's important to know that the curly braces are *not* part of the
91
+ variable but the print statement. If you access variables inside tags
92
+ don't put the braces around.
93
+
94
+ If a variable or attribute does not exist, you will get back a ``null`` value
95
+ when the ``strict_variables`` option is set to ``false``, otherwise Twig will
96
+ throw an error (see :ref:`environment options<environment_options>`).
97
+
98
+ .. sidebar:: Implementation
99
+
100
+ For convenience sake ``foo.bar`` does the following things on the PHP
101
+ layer:
102
+
103
+ * check if ``foo`` is an array and ``bar`` a valid element;
104
+ * if not, and if ``foo`` is an object, check that ``bar`` is a valid property;
105
+ * if not, and if ``foo`` is an object, check that ``bar`` is a valid method
106
+ (even if ``bar`` is the constructor - use ``__construct()`` instead);
107
+ * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method;
108
+ * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method;
109
+ * if not, return a ``null`` value.
110
+
111
+ ``foo['bar']`` on the other hand only works with PHP arrays:
112
+
113
+ * check if ``foo`` is an array and ``bar`` a valid element;
114
+ * if not, return a ``null`` value.
115
+
116
+ .. note::
117
+
118
+ If you want to get a dynamic attribute on a variable, use the
119
+ :doc:`attribute<functions/attribute>` function instead.
120
+
121
+ Global Variables
122
+ ~~~~~~~~~~~~~~~~
123
+
124
+ The following variables are always available in templates:
125
+
126
+ * ``_self``: references the current template;
127
+ * ``_context``: references the current context;
128
+ * ``_charset``: references the current charset.
129
+
130
+ Setting Variables
131
+ ~~~~~~~~~~~~~~~~~
132
+
133
+ You can assign values to variables inside code blocks. Assignments use the
134
+ :doc:`set<tags/set>` tag:
135
+
136
+ .. code-block:: jinja
137
+
138
+ {% set foo = 'foo' %}
139
+ {% set foo = [1, 2] %}
140
+ {% set foo = {'foo': 'bar'} %}
141
+
142
+ Filters
143
+ -------
144
+
145
+ Variables can be modified by **filters**. Filters are separated from the
146
+ variable by a pipe symbol (``|``) and may have optional arguments in
147
+ parentheses. Multiple filters can be chained. The output of one filter is
148
+ applied to the next.
149
+
150
+ The following example removes all HTML tags from the ``name`` and title-cases
151
+ it:
152
+
153
+ .. code-block:: jinja
154
+
155
+ {{ name|striptags|title }}
156
+
157
+ Filters that accept arguments have parentheses around the arguments. This
158
+ example will join a list by commas:
159
+
160
+ .. code-block:: jinja
161
+
162
+ {{ list|join(', ') }}
163
+
164
+ To apply a filter on a section of code, wrap it with the
165
+ :doc:`filter<tags/filter>` tag:
166
+
167
+ .. code-block:: jinja
168
+
169
+ {% filter upper %}
170
+ This text becomes uppercase
171
+ {% endfilter %}
172
+
173
+ Go to the :doc:`filters<filters/index>` page to learn more about the built-in
174
+ filters.
175
+
176
+ Functions
177
+ ---------
178
+
179
+ Functions can be called to generate content. Functions are called by their
180
+ name followed by parentheses (``()``) and may have arguments.
181
+
182
+ For instance, the ``range`` function returns a list containing an arithmetic
183
+ progression of integers:
184
+
185
+ .. code-block:: jinja
186
+
187
+ {% for i in range(0, 3) %}
188
+ {{ i }},
189
+ {% endfor %}
190
+
191
+ Go to the :doc:`functions<functions/index>` page to learn more about the
192
+ built-in functions.
193
+
194
+ Named Arguments
195
+ ---------------
196
+
197
+ .. versionadded:: 1.12
198
+ Support for named arguments was added in Twig 1.12.
199
+
200
+ .. code-block:: jinja
201
+
202
+ {% for i in range(low=1, high=10, step=2) %}
203
+ {{ i }},
204
+ {% endfor %}
205
+
206
+ Using named arguments makes your templates more explicit about the meaning of
207
+ the values you pass as arguments:
208
+
209
+ .. code-block:: jinja
210
+
211
+ {{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
212
+
213
+ {# versus #}
214
+
215
+ {{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
216
+
217
+ Named arguments also allow you to skip some arguments for which you don't want
218
+ to change the default value:
219
+
220
+ .. code-block:: jinja
221
+
222
+ {# the first argument is the date format, which defaults to the global date format if null is passed #}
223
+ {{ "now"|date(null, "Europe/Paris") }}
224
+
225
+ {# or skip the format value by using a named argument for the timezone #}
226
+ {{ "now"|date(timezone="Europe/Paris") }}
227
+
228
+ You can also use both positional and named arguments in one call, in which
229
+ case positional arguments must always come before named arguments:
230
+
231
+ .. code-block:: jinja
232
+
233
+ {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}
234
+
235
+ .. tip::
236
+
237
+ Each function and filter documentation page has a section where the names
238
+ of all arguments are listed when supported.
239
+
240
+ Control Structure
241
+ -----------------
242
+
243
+ A control structure refers to all those things that control the flow of a
244
+ program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as
245
+ well as things like blocks. Control structures appear inside ``{% ... %}``
246
+ blocks.
247
+
248
+ For example, to display a list of users provided in a variable called
249
+ ``users``, use the :doc:`for<tags/for>` tag:
250
+
251
+ .. code-block:: jinja
252
+
253
+ <h1>Members</h1>
254
+ <ul>
255
+ {% for user in users %}
256
+ <li>{{ user.username|e }}</li>
257
+ {% endfor %}
258
+ </ul>
259
+
260
+ The :doc:`if<tags/if>` tag can be used to test an expression:
261
+
262
+ .. code-block:: jinja
263
+
264
+ {% if users|length > 0 %}
265
+ <ul>
266
+ {% for user in users %}
267
+ <li>{{ user.username|e }}</li>
268
+ {% endfor %}
269
+ </ul>
270
+ {% endif %}
271
+
272
+ Go to the :doc:`tags<tags/index>` page to learn more about the built-in tags.
273
+
274
+ Comments
275
+ --------
276
+
277
+ To comment-out part of a line in a template, use the comment syntax ``{# ...
278
+ #}``. This is useful for debugging or to add information for other template
279
+ designers or yourself:
280
+
281
+ .. code-block:: jinja
282
+
283
+ {# note: disabled template because we no longer use this
284
+ {% for user in users %}
285
+ ...
286
+ {% endfor %}
287
+ #}
288
+
289
+ Including other Templates
290
+ -------------------------
291
+
292
+ The :doc:`include<tags/include>` tag is useful to include a template and
293
+ return the rendered content of that template into the current one:
294
+
295
+ .. code-block:: jinja
296
+
297
+ {% include 'sidebar.html' %}
298
+
299
+ Per default included templates are passed the current context.
300
+
301
+ The context that is passed to the included template includes variables defined
302
+ in the template:
303
+
304
+ .. code-block:: jinja
305
+
306
+ {% for box in boxes %}
307
+ {% include "render_box.html" %}
308
+ {% endfor %}
309
+
310
+ The included template ``render_box.html`` is able to access ``box``.
311
+
312
+ The filename of the template depends on the template loader. For instance, the
313
+ ``Twig_Loader_Filesystem`` allows you to access other templates by giving the
314
+ filename. You can access templates in subdirectories with a slash:
315
+
316
+ .. code-block:: jinja
317
+
318
+ {% include "sections/articles/sidebar.html" %}
319
+
320
+ This behavior depends on the application embedding Twig.
321
+
322
+ Template Inheritance
323
+ --------------------
324
+
325
+ The most powerful part of Twig is template inheritance. Template inheritance
326
+ allows you to build a base "skeleton" template that contains all the common
327
+ elements of your site and defines **blocks** that child templates can
328
+ override.
329
+
330
+ Sounds complicated but is very basic. It's easier to understand it by
331
+ starting with an example.
332
+
333
+ Let's define a base template, ``base.html``, which defines a simple HTML
334
+ skeleton document that you might use for a simple two-column page:
335
+
336
+ .. code-block:: html+jinja
337
+
338
+ <!DOCTYPE html>
339
+ <html>
340
+ <head>
341
+ {% block head %}
342
+ <link rel="stylesheet" href="style.css" />
343
+ <title>{% block title %}{% endblock %} - My Webpage</title>
344
+ {% endblock %}
345
+ </head>
346
+ <body>
347
+ <div id="content">{% block content %}{% endblock %}</div>
348
+ <div id="footer">
349
+ {% block footer %}
350
+ &copy; Copyright 2011 by <a href="http://domain.invalid/">you</a>.
351
+ {% endblock %}
352
+ </div>
353
+ </body>
354
+ </html>
355
+
356
+ In this example, the :doc:`block<tags/block>` tags define four blocks that
357
+ child templates can fill in. All the ``block`` tag does is to tell the
358
+ template engine that a child template may override those portions of the
359
+ template.
360
+
361
+ A child template might look like this:
362
+
363
+ .. code-block:: jinja
364
+
365
+ {% extends "base.html" %}
366
+
367
+ {% block title %}Index{% endblock %}
368
+ {% block head %}
369
+ {{ parent() }}
370
+ <style type="text/css">
371
+ .important { color: #336699; }
372
+ </style>
373
+ {% endblock %}
374
+ {% block content %}
375
+ <h1>Index</h1>
376
+ <p class="important">
377
+ Welcome to my awesome homepage.
378
+ </p>
379
+ {% endblock %}
380
+
381
+ The :doc:`extends<tags/extends>` tag is the key here. It tells the template
382
+ engine that this template "extends" another template. When the template system
383
+ evaluates this template, first it locates the parent. The extends tag should
384
+ be the first tag in the template.
385
+
386
+ Note that since the child template doesn't define the ``footer`` block, the
387
+ value from the parent template is used instead.
388
+
389
+ It's possible to render the contents of the parent block by using the
390
+ :doc:`parent<functions/parent>` function. This gives back the results of the
391
+ parent block:
392
+
393
+ .. code-block:: jinja
394
+
395
+ {% block sidebar %}
396
+ <h3>Table Of Contents</h3>
397
+ ...
398
+ {{ parent() }}
399
+ {% endblock %}
400
+
401
+ .. tip::
402
+
403
+ The documentation page for the :doc:`extends<tags/extends>` tag describes
404
+ more advanced features like block nesting, scope, dynamic inheritance, and
405
+ conditional inheritance.
406
+
407
+ .. note::
408
+
409
+ Twig also supports multiple inheritance with the so called horizontal reuse
410
+ with the help of the :doc:`use<tags/use>` tag. This is an advanced feature
411
+ hardly ever needed in regular templates.
412
+
413
+ HTML Escaping
414
+ -------------
415
+
416
+ When generating HTML from templates, there's always a risk that a variable
417
+ will include characters that affect the resulting HTML. There are two
418
+ approaches: manually escaping each variable or automatically escaping
419
+ everything by default.
420
+
421
+ Twig supports both, automatic escaping is enabled by default.
422
+
423
+ .. note::
424
+
425
+ Automatic escaping is only supported if the *escaper* extension has been
426
+ enabled (which is the default).
427
+
428
+ Working with Manual Escaping
429
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
430
+
431
+ If manual escaping is enabled, it is **your** responsibility to escape
432
+ variables if needed. What to escape? Any variable you don't trust.
433
+
434
+ Escaping works by piping the variable through the
435
+ :doc:`escape<filters/escape>` or ``e`` filter:
436
+
437
+ .. code-block:: jinja
438
+
439
+ {{ user.username|e }}
440
+
441
+ By default, the ``escape`` filter uses the ``html`` strategy, but depending on
442
+ the escaping context, you might want to explicitly use any other available
443
+ strategies:
444
+
445
+ .. code-block:: jinja
446
+
447
+ {{ user.username|e('js') }}
448
+ {{ user.username|e('css') }}
449
+ {{ user.username|e('url') }}
450
+ {{ user.username|e('html_attr') }}
451
+
452
+ Working with Automatic Escaping
453
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
454
+
455
+ Whether automatic escaping is enabled or not, you can mark a section of a
456
+ template to be escaped or not by using the :doc:`autoescape<tags/autoescape>`
457
+ tag:
458
+
459
+ .. code-block:: jinja
460
+
461
+ {% autoescape %}
462
+ Everything will be automatically escaped in this block (using the HTML strategy)
463
+ {% endautoescape %}
464
+
465
+ By default, auto-escaping uses the ``html`` escaping strategy. If you output
466
+ variables in other contexts, you need to explicitly escape them with the
467
+ appropriate escaping strategy:
468
+
469
+ .. code-block:: jinja
470
+
471
+ {% autoescape 'js' %}
472
+ Everything will be automatically escaped in this block (using the JS strategy)
473
+ {% endautoescape %}
474
+
475
+ Escaping
476
+ --------
477
+
478
+ It is sometimes desirable or even necessary to have Twig ignore parts it would
479
+ otherwise handle as variables or blocks. For example if the default syntax is
480
+ used and you want to use ``{{`` as raw string in the template and not start a
481
+ variable you have to use a trick.
482
+
483
+ The easiest way is to output the variable delimiter (``{{``) by using a variable
484
+ expression:
485
+
486
+ .. code-block:: jinja
487
+
488
+ {{ '{{' }}
489
+
490
+ For bigger sections it makes sense to mark a block
491
+ :doc:`verbatim<tags/verbatim>`.
492
+
493
+ Macros
494
+ ------
495
+
496
+ .. versionadded:: 1.12
497
+ Support for default argument values was added in Twig 1.12.
498
+
499
+ Macros are comparable with functions in regular programming languages. They
500
+ are useful to reuse often used HTML fragments to not repeat yourself.
501
+
502
+ A macro is defined via the :doc:`macro<tags/macro>` tag. Here is a small example
503
+ (subsequently called ``forms.html``) of a macro that renders a form element:
504
+
505
+ .. code-block:: jinja
506
+
507
+ {% macro input(name, value, type, size) %}
508
+ <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
509
+ {% endmacro %}
510
+
511
+ Macros can be defined in any template, and need to be "imported" via the
512
+ :doc:`import<tags/import>` tag before being used:
513
+
514
+ .. code-block:: jinja
515
+
516
+ {% import "forms.html" as forms %}
517
+
518
+ <p>{{ forms.input('username') }}</p>
519
+
520
+ Alternatively, you can import individual macro names from a template into the
521
+ current namespace via the :doc:`from<tags/from>` tag and optionally alias them:
522
+
523
+ .. code-block:: jinja
524
+
525
+ {% from 'forms.html' import input as input_field %}
526
+
527
+ <dl>
528
+ <dt>Username</dt>
529
+ <dd>{{ input_field('username') }}</dd>
530
+ <dt>Password</dt>
531
+ <dd>{{ input_field('password', '', 'password') }}</dd>
532
+ </dl>
533
+
534
+ A default value can also be defined for macro arguments when not provided in a
535
+ macro call:
536
+
537
+ .. code-block:: jinja
538
+
539
+ {% macro input(name, value = "", type = "text", size = 20) %}
540
+ <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
541
+ {% endmacro %}
542
+
543
+ .. _twig-expressions:
544
+
545
+ Expressions
546
+ -----------
547
+
548
+ Twig allows expressions everywhere. These work very similar to regular PHP and
549
+ even if you're not working with PHP you should feel comfortable with it.
550
+
551
+ .. note::
552
+
553
+ The operator precedence is as follows, with the lowest-precedence
554
+ operators listed first: ``b-and``, ``b-xor``, ``b-or``, ``or``, ``and``,
555
+ ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``matches``,
556
+ ``starts with``, ``ends with``, ``..``, ``+``, ``-``, ``~``, ``*``, ``/``,
557
+ ``//``, ``%``, ``is``, ``**``, ``|``, ``[]``, and ``.``:
558
+
559
+ .. code-block:: jinja
560
+
561
+ {% set greeting = 'Hello ' %}
562
+ {% set name = 'Fabien' %}
563
+
564
+ {{ greeting ~ name|lower }} {# Hello fabien #}
565
+
566
+ {# use parenthesis to change precedence #}
567
+ {{ (greeting ~ name)|lower }} {# hello fabien #}
568
+
569
+ Literals
570
+ ~~~~~~~~
571
+
572
+ .. versionadded:: 1.5
573
+ Support for hash keys as names and expressions was added in Twig 1.5.
574
+
575
+ The simplest form of expressions are literals. Literals are representations
576
+ for PHP types such as strings, numbers, and arrays. The following literals
577
+ exist:
578
+
579
+ * ``"Hello World"``: Everything between two double or single quotes is a
580
+ string. They are useful whenever you need a string in the template (for
581
+ example as arguments to function calls, filters or just to extend or include
582
+ a template). A string can contain a delimiter if it is preceded by a
583
+ backslash (``\``) -- like in ``'It\'s good'``.
584
+
585
+ * ``42`` / ``42.23``: Integers and floating point numbers are created by just
586
+ writing the number down. If a dot is present the number is a float,
587
+ otherwise an integer.
588
+
589
+ * ``["foo", "bar"]``: Arrays are defined by a sequence of expressions
590
+ separated by a comma (``,``) and wrapped with squared brackets (``[]``).
591
+
592
+ * ``{"foo": "bar"}``: Hashes are defined by a list of keys and values
593
+ separated by a comma (``,``) and wrapped with curly braces (``{}``):
594
+
595
+ .. code-block:: jinja
596
+
597
+ {# keys as string #}
598
+ { 'foo': 'foo', 'bar': 'bar' }
599
+
600
+ {# keys as names (equivalent to the previous hash) -- as of Twig 1.5 #}
601
+ { foo: 'foo', bar: 'bar' }
602
+
603
+ {# keys as integer #}
604
+ { 2: 'foo', 4: 'bar' }
605
+
606
+ {# keys as expressions (the expression must be enclosed into parentheses) -- as of Twig 1.5 #}
607
+ { (1 + 1): 'foo', (a ~ 'b'): 'bar' }
608
+
609
+ * ``true`` / ``false``: ``true`` represents the true value, ``false``
610
+ represents the false value.
611
+
612
+ * ``null``: ``null`` represents no specific value. This is the value returned
613
+ when a variable does not exist. ``none`` is an alias for ``null``.
614
+
615
+ Arrays and hashes can be nested:
616
+
617
+ .. code-block:: jinja
618
+
619
+ {% set foo = [1, {"foo": "bar"}] %}
620
+
621
+ .. tip::
622
+
623
+ Using double-quoted or single-quoted strings has no impact on performance
624
+ but string interpolation is only supported in double-quoted strings.
625
+
626
+ Math
627
+ ~~~~
628
+
629
+ Twig allows you to calculate with values. This is rarely useful in templates
630
+ but exists for completeness' sake. The following operators are supported:
631
+
632
+ * ``+``: Adds two objects together (the operands are casted to numbers). ``{{
633
+ 1 + 1 }}`` is ``2``.
634
+
635
+ * ``-``: Subtracts the second number from the first one. ``{{ 3 - 2 }}`` is
636
+ ``1``.
637
+
638
+ * ``/``: Divides two numbers. The returned value will be a floating point
639
+ number. ``{{ 1 / 2 }}`` is ``{{ 0.5 }}``.
640
+
641
+ * ``%``: Calculates the remainder of an integer division. ``{{ 11 % 7 }}`` is
642
+ ``4``.
643
+
644
+ * ``//``: Divides two numbers and returns the floored integer result. ``{{ 20
645
+ // 7 }}`` is ``2``, ``{{ -20 // 7 }}`` is ``-3`` (this is just syntactic
646
+ sugar for the :doc:`round<filters/round>` filter).
647
+
648
+ * ``*``: Multiplies the left operand with the right one. ``{{ 2 * 2 }}`` would
649
+ return ``4``.
650
+
651
+ * ``**``: Raises the left operand to the power of the right operand. ``{{ 2 **
652
+ 3 }}`` would return ``8``.
653
+
654
+ Logic
655
+ ~~~~~
656
+
657
+ You can combine multiple expressions with the following operators:
658
+
659
+ * ``and``: Returns true if the left and the right operands are both true.
660
+
661
+ * ``or``: Returns true if the left or the right operand is true.
662
+
663
+ * ``not``: Negates a statement.
664
+
665
+ * ``(expr)``: Groups an expression.
666
+
667
+ .. note::
668
+
669
+ Twig also support bitwise operators (``b-and``, ``b-xor``, and ``b-or``).
670
+
671
+ Comparisons
672
+ ~~~~~~~~~~~
673
+
674
+ The following comparison operators are supported in any expression: ``==``,
675
+ ``!=``, ``<``, ``>``, ``>=``, and ``<=``.
676
+
677
+ You can also check if a string ``starts with`` or ``ends with`` another
678
+ string:
679
+
680
+ .. code-block:: jinja
681
+
682
+ {% if 'Fabien' starts with 'F' %}
683
+ {% endif %}
684
+
685
+ {% if 'Fabien' ends with 'n' %}
686
+ {% endif %}
687
+
688
+ .. note::
689
+
690
+ For complex string comparisons, the ``matches`` operator allows you to use
691
+ `regular expressions`_:
692
+
693
+ .. code-block:: jinja
694
+
695
+ {% if phone matches '{^[\d\.]+$}' %}
696
+ {% endif %}
697
+
698
+ Containment Operator
699
+ ~~~~~~~~~~~~~~~~~~~~
700
+
701
+ The ``in`` operator performs containment test.
702
+
703
+ It returns ``true`` if the left operand is contained in the right:
704
+
705
+ .. code-block:: jinja
706
+
707
+ {# returns true #}
708
+
709
+ {{ 1 in [1, 2, 3] }}
710
+
711
+ {{ 'cd' in 'abcde' }}
712
+
713
+ .. tip::
714
+
715
+ You can use this filter to perform a containment test on strings, arrays,
716
+ or objects implementing the ``Traversable`` interface.
717
+
718
+ To perform a negative test, use the ``not in`` operator:
719
+
720
+ .. code-block:: jinja
721
+
722
+ {% if 1 not in [1, 2, 3] %}
723
+
724
+ {# is equivalent to #}
725
+ {% if not (1 in [1, 2, 3]) %}
726
+
727
+ Test Operator
728
+ ~~~~~~~~~~~~~
729
+
730
+ The ``is`` operator performs tests. Tests can be used to test a variable against
731
+ a common expression. The right operand is name of the test:
732
+
733
+ .. code-block:: jinja
734
+
735
+ {# find out if a variable is odd #}
736
+
737
+ {{ name is odd }}
738
+
739
+ Tests can accept arguments too:
740
+
741
+ .. code-block:: jinja
742
+
743
+ {% if post.status is constant('Post::PUBLISHED') %}
744
+
745
+ Tests can be negated by using the ``is not`` operator:
746
+
747
+ .. code-block:: jinja
748
+
749
+ {% if post.status is not constant('Post::PUBLISHED') %}
750
+
751
+ {# is equivalent to #}
752
+ {% if not (post.status is constant('Post::PUBLISHED')) %}
753
+
754
+ Go to the :doc:`tests<tests/index>` page to learn more about the built-in
755
+ tests.
756
+
757
+ Other Operators
758
+ ~~~~~~~~~~~~~~~
759
+
760
+ .. versionadded:: 1.12.0
761
+ Support for the extended ternary operator was added in Twig 1.12.0.
762
+
763
+ The following operators are very useful but don't fit into any of the other
764
+ categories:
765
+
766
+ * ``..``: Creates a sequence based on the operand before and after the
767
+ operator (this is just syntactic sugar for the :doc:`range<functions/range>`
768
+ function).
769
+
770
+ * ``|``: Applies a filter.
771
+
772
+ * ``~``: Converts all operands into strings and concatenates them. ``{{ "Hello
773
+ " ~ name ~ "!" }}`` would return (assuming ``name`` is ``'John'``) ``Hello
774
+ John!``.
775
+
776
+ * ``.``, ``[]``: Gets an attribute of an object.
777
+
778
+ * ``?:``: The ternary operator:
779
+
780
+ .. code-block:: jinja
781
+
782
+ {{ foo ? 'yes' : 'no' }}
783
+
784
+ {# as of Twig 1.12.0 #}
785
+ {{ foo ?: 'no' }} is the same as {{ foo ? foo : 'no' }}
786
+ {{ foo ? 'yes' }} is the same as {{ foo ? 'yes' : '' }}
787
+
788
+ String Interpolation
789
+ ~~~~~~~~~~~~~~~~~~~~
790
+
791
+ .. versionadded:: 1.5
792
+ String interpolation was added in Twig 1.5.
793
+
794
+ String interpolation (`#{expression}`) allows any valid expression to appear
795
+ within a *double-quoted string*. The result of evaluating that expression is
796
+ inserted into the string:
797
+
798
+ .. code-block:: jinja
799
+
800
+ {{ "foo #{bar} baz" }}
801
+ {{ "foo #{1 + 2} baz" }}
802
+
803
+ Whitespace Control
804
+ ------------------
805
+
806
+ .. versionadded:: 1.1
807
+ Tag level whitespace control was added in Twig 1.1.
808
+
809
+ The first newline after a template tag is removed automatically (like in PHP.)
810
+ Whitespace is not further modified by the template engine, so each whitespace
811
+ (spaces, tabs, newlines etc.) is returned unchanged.
812
+
813
+ Use the ``spaceless`` tag to remove whitespace *between HTML tags*:
814
+
815
+ .. code-block:: jinja
816
+
817
+ {% spaceless %}
818
+ <div>
819
+ <strong>foo bar</strong>
820
+ </div>
821
+ {% endspaceless %}
822
+
823
+ {# output will be <div><strong>foo bar</strong></div> #}
824
+
825
+ In addition to the spaceless tag you can also control whitespace on a per tag
826
+ level. By using the whitespace control modifier on your tags, you can trim
827
+ leading and or trailing whitespace:
828
+
829
+ .. code-block:: jinja
830
+
831
+ {% set value = 'no spaces' %}
832
+ {#- No leading/trailing whitespace -#}
833
+ {%- if true -%}
834
+ {{- value -}}
835
+ {%- endif -%}
836
+
837
+ {# output 'no spaces' #}
838
+
839
+ The above sample shows the default whitespace control modifier, and how you can
840
+ use it to remove whitespace around tags. Trimming space will consume all whitespace
841
+ for that side of the tag. It is possible to use whitespace trimming on one side
842
+ of a tag:
843
+
844
+ .. code-block:: jinja
845
+
846
+ {% set value = 'no spaces' %}
847
+ <li> {{- value }} </li>
848
+
849
+ {# outputs '<li>no spaces </li>' #}
850
+
851
+ Extensions
852
+ ----------
853
+
854
+ Twig can be easily extended.
855
+
856
+ If you are looking for new tags, filters, or functions, have a look at the Twig official
857
+ `extension repository`_.
858
+
859
+ If you want to create your own, read the :ref:`Creating an
860
+ Extension<creating_extensions>` chapter.
861
+
862
+ .. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle
863
+ .. _`Jinja syntax plugin`: http://jinja.pocoo.org/docs/integration/#vim
864
+ .. _`vim-twig plugin`: https://github.com/evidens/vim-twig
865
+ .. _`Twig syntax plugin`: http://plugins.netbeans.org/plugin/37069/php-twig
866
+ .. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin
867
+ .. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language
868
+ .. _`extension repository`: http://github.com/fabpot/Twig-extensions
869
+ .. _`Twig syntax mode`: https://github.com/bobthecow/Twig-HTML.mode
870
+ .. _`other Twig syntax mode`: https://github.com/muxx/Twig-HTML.mode
871
+ .. _`Notepad++ Twig Highlighter`: https://github.com/Banane9/notepadplusplus-twig
872
+ .. _`web-mode.el`: http://web-mode.org/
873
+ .. _`regular expressions`: http://php.net/manual/en/pcre.pattern.php
vendor/vendor/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 %}
vendor/vendor/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 %}
vendor/vendor/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 %}
vendor/vendor/twig/twig/doc/tests/empty.rst ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ``empty``
2
+ =========
3
+
4
+ ``empty`` checks if a variable is empty:
5
+
6
+ .. code-block:: jinja
7
+
8
+ {# evaluates to true if the foo variable is null, false, an empty array, or the empty string #}
9
+ {% if foo is empty %}
10
+ ...
11
+ {% endif %}
vendor/vendor/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>`
vendor/vendor/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
vendor/vendor/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 %}
vendor/vendor/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``.
vendor/vendor/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>`
vendor/vendor/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 points to the same memory address than
8
+ another variable:
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 %}
vendor/vendor/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
vendor/vendor/twig/twig/ext/twig/LICENSE ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
2
+
3
+ Some rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are
7
+ met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above
13
+ copyright notice, this list of conditions and the following
14
+ disclaimer in the documentation and/or other materials provided
15
+ with the distribution.
16
+
17
+ * The names of the contributors may not be used to endorse or
18
+ promote products derived from this software without specific
19
+ prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
vendor/vendor/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
vendor/vendor/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
+ }
vendor/vendor/twig/twig/ext/twig/php_twig.h ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.15.1"
19
+
20
+ #include "php.h"
21
+
22
+ extern zend_module_entry twig_module_entry;
23
+ #define phpext_twig_ptr &twig_module_entry
24
+
25
+ #ifdef ZTS
26
+ #include "TSRM.h"
27
+ #endif
28
+
29
+ PHP_FUNCTION(twig_template_get_attributes);
30
+
31
+ #endif
vendor/vendor/twig/twig/ext/twig/twig.c ADDED
@@ -0,0 +1,1101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ #define FREE_DTOR(z) \
35
+ zval_dtor(z); \
36
+ efree(z);
37
+
38
+ #if PHP_VERSION_ID >= 50300
39
+ #define APPLY_TSRMLS_DC TSRMLS_DC
40
+ #define APPLY_TSRMLS_CC TSRMLS_CC
41
+ #define APPLY_TSRMLS_FETCH()
42
+ #else
43
+ #define APPLY_TSRMLS_DC
44
+ #define APPLY_TSRMLS_CC
45
+ #define APPLY_TSRMLS_FETCH() TSRMLS_FETCH()
46
+ #endif
47
+
48
+ ZEND_BEGIN_ARG_INFO_EX(twig_template_get_attribute_args, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 6)
49
+ ZEND_ARG_INFO(0, template)
50
+ ZEND_ARG_INFO(0, object)
51
+ ZEND_ARG_INFO(0, item)
52
+ ZEND_ARG_INFO(0, arguments)
53
+ ZEND_ARG_INFO(0, type)
54
+ ZEND_ARG_INFO(0, isDefinedTest)
55
+ ZEND_END_ARG_INFO()
56
+
57
+ zend_function_entry twig_functions[] = {
58
+ PHP_FE(twig_template_get_attributes, twig_template_get_attribute_args)
59
+ {NULL, NULL, NULL}
60
+ };
61
+
62
+
63
+ zend_module_entry twig_module_entry = {
64
+ STANDARD_MODULE_HEADER,
65
+ "twig",
66
+ twig_functions,
67
+ NULL,
68
+ NULL,
69
+ NULL,
70
+ NULL,
71
+ NULL,
72
+ PHP_TWIG_VERSION,
73
+ STANDARD_MODULE_PROPERTIES
74
+ };
75
+
76
+
77
+ #ifdef COMPILE_DL_TWIG
78
+ ZEND_GET_MODULE(twig)
79
+ #endif
80
+
81
+ int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
82
+ {
83
+ if (Z_TYPE_P(array) != IS_ARRAY) {
84
+ return 0;
85
+ }
86
+
87
+ switch (Z_TYPE_P(key)) {
88
+ case IS_NULL:
89
+ return zend_hash_exists(Z_ARRVAL_P(array), "", 1);
90
+
91
+ case IS_BOOL:
92
+ case IS_DOUBLE:
93
+ convert_to_long(key);
94
+ case IS_LONG:
95
+ return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key));
96
+
97
+ default:
98
+ convert_to_string(key);
99
+ return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1);
100
+ }
101
+ }
102
+
103
+ int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
104
+ {
105
+ if (Z_TYPE_P(object) != IS_OBJECT) {
106
+ return 0;
107
+ }
108
+ return instanceof_function(Z_OBJCE_P(object), interface TSRMLS_CC);
109
+ }
110
+
111
+ int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
112
+ {
113
+ zend_class_entry **pce;
114
+ if (Z_TYPE_P(object) != IS_OBJECT) {
115
+ return 0;
116
+ }
117
+ if (zend_lookup_class(interface, strlen(interface), &pce TSRMLS_CC) == FAILURE) {
118
+ return 0;
119
+ }
120
+ return instanceof_function(Z_OBJCE_P(object), *pce TSRMLS_CC);
121
+ }
122
+
123
+ zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
124
+ {
125
+ zend_class_entry *ce = Z_OBJCE_P(object);
126
+ zval *retval;
127
+
128
+ if (Z_TYPE_P(object) == IS_OBJECT) {
129
+ SEPARATE_ARG_IF_REF(offset);
130
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
131
+
132
+ zval_ptr_dtor(&offset);
133
+
134
+ if (!retval) {
135
+ if (!EG(exception)) {
136
+ zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
137
+ }
138
+ return NULL;
139
+ }
140
+
141
+ return retval;
142
+ }
143
+ return NULL;
144
+ }
145
+
146
+ int TWIG_ISSET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
147
+ {
148
+ zend_class_entry *ce = Z_OBJCE_P(object);
149
+ zval *retval;
150
+
151
+ if (Z_TYPE_P(object) == IS_OBJECT) {
152
+ SEPARATE_ARG_IF_REF(offset);
153
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
154
+
155
+ zval_ptr_dtor(&offset);
156
+
157
+ if (!retval) {
158
+ if (!EG(exception)) {
159
+ zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
160
+ }
161
+ return 0;
162
+ }
163
+
164
+ return (retval && Z_TYPE_P(retval) == IS_BOOL && Z_LVAL_P(retval));
165
+ }
166
+ return 0;
167
+ }
168
+
169
+ char *TWIG_STRTOLOWER(const char *str, int str_len)
170
+ {
171
+ char *item_dup;
172
+
173
+ item_dup = estrndup(str, str_len);
174
+ php_strtolower(item_dup, str_len);
175
+ return item_dup;
176
+ }
177
+
178
+ zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TSRMLS_DC)
179
+ {
180
+ zend_fcall_info fci;
181
+ zval ***args = NULL;
182
+ int arg_count = 0;
183
+ HashTable *table;
184
+ HashPosition pos;
185
+ int i = 0;
186
+ zval *retval_ptr;
187
+ zval *zfunction;
188
+
189
+ if (arguments) {
190
+ table = HASH_OF(arguments);
191
+ args = safe_emalloc(sizeof(zval **), table->nNumOfElements, 0);
192
+
193
+ zend_hash_internal_pointer_reset_ex(table, &pos);
194
+
195
+ while (zend_hash_get_current_data_ex(table, (void **)&args[i], &pos) == SUCCESS) {
196
+ i++;
197
+ zend_hash_move_forward_ex(table, &pos);
198
+ }
199
+ arg_count = table->nNumOfElements;
200
+ }
201
+
202
+ MAKE_STD_ZVAL(zfunction);
203
+ ZVAL_STRING(zfunction, function, 1);
204
+ fci.size = sizeof(fci);
205
+ fci.function_table = EG(function_table);
206
+ fci.function_name = zfunction;
207
+ fci.symbol_table = NULL;
208
+ #if PHP_VERSION_ID >= 50300
209
+ fci.object_ptr = object;
210
+ #else
211
+ fci.object_pp = &object;
212
+ #endif
213
+ fci.retval_ptr_ptr = &retval_ptr;
214
+ fci.param_count = arg_count;
215
+ fci.params = args;
216
+ fci.no_separation = 0;
217
+
218
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
219
+ ALLOC_INIT_ZVAL(retval_ptr);
220
+ ZVAL_BOOL(retval_ptr, 0);
221
+ }
222
+
223
+ if (args) {
224
+ efree(fci.params);
225
+ }
226
+ FREE_DTOR(zfunction);
227
+ return retval_ptr;
228
+ }
229
+
230
+ int TWIG_CALL_BOOLEAN(zval *object, char *functionName TSRMLS_DC)
231
+ {
232
+ zval *ret;
233
+ int res;
234
+
235
+ ret = TWIG_CALL_USER_FUNC_ARRAY(object, functionName, NULL TSRMLS_CC);
236
+ res = Z_LVAL_P(ret);
237
+ zval_ptr_dtor(&ret);
238
+ return res;
239
+ }
240
+
241
+ zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC)
242
+ {
243
+ zval **tmp_zval;
244
+ zend_class_entry *ce;
245
+
246
+ if (class == NULL || Z_TYPE_P(class) != IS_OBJECT) {
247
+ return NULL;
248
+ }
249
+
250
+ ce = zend_get_class_entry(class TSRMLS_CC);
251
+ #if PHP_VERSION_ID >= 50400
252
+ tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0, NULL TSRMLS_CC);
253
+ #else
254
+ tmp_zval = zend_std_get_static_property(ce, prop_name, strlen(prop_name), 0 TSRMLS_CC);
255
+ #endif
256
+ return *tmp_zval;
257
+ }
258
+
259
+ zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
260
+ {
261
+ zval **tmp_zval;
262
+
263
+ if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) {
264
+ if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
265
+ // array access object
266
+ return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC);
267
+ }
268
+ return NULL;
269
+ }
270
+
271
+ switch(Z_TYPE_P(prop_name)) {
272
+ case IS_NULL:
273
+ zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval);
274
+ return *tmp_zval;
275
+
276
+ case IS_BOOL:
277
+ case IS_DOUBLE:
278
+ convert_to_long(prop_name);
279
+ case IS_LONG:
280
+ zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval);
281
+ return *tmp_zval;
282
+
283
+ case IS_STRING:
284
+ zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval);
285
+ return *tmp_zval;
286
+ }
287
+
288
+ return NULL;
289
+ }
290
+
291
+ zval *TWIG_GET_ARRAY_ELEMENT(zval *class, char *prop_name, int prop_name_length TSRMLS_DC)
292
+ {
293
+ zval **tmp_zval;
294
+
295
+ if (class == NULL/* || Z_TYPE_P(class) != IS_ARRAY*/) {
296
+ return NULL;
297
+ }
298
+
299
+ if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
300
+ // array access object
301
+ zval *tmp_name_zval;
302
+ zval *tmp_ret_zval;
303
+
304
+ ALLOC_INIT_ZVAL(tmp_name_zval);
305
+ ZVAL_STRING(tmp_name_zval, prop_name, 1);
306
+ tmp_ret_zval = TWIG_GET_ARRAYOBJECT_ELEMENT(class, tmp_name_zval TSRMLS_CC);
307
+ FREE_DTOR(tmp_name_zval);
308
+ return tmp_ret_zval;
309
+ }
310
+
311
+ if (zend_symtable_find(HASH_OF(class), prop_name, prop_name_length+1, (void**)&tmp_zval) == SUCCESS) {
312
+ return *tmp_zval;
313
+ }
314
+ return NULL;
315
+ }
316
+
317
+ zval *TWIG_PROPERTY(zval *object, zval *propname TSRMLS_DC)
318
+ {
319
+ zval *tmp = NULL;
320
+
321
+ if (Z_OBJ_HT_P(object)->read_property) {
322
+ #if PHP_VERSION_ID >= 50400
323
+ tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS, NULL TSRMLS_CC);
324
+ #else
325
+ tmp = Z_OBJ_HT_P(object)->read_property(object, propname, BP_VAR_IS TSRMLS_CC);
326
+ #endif
327
+ if (tmp == EG(uninitialized_zval_ptr)) {
328
+ ZVAL_NULL(tmp);
329
+ }
330
+ }
331
+ return tmp;
332
+ }
333
+
334
+ int TWIG_HAS_PROPERTY(zval *object, zval *propname TSRMLS_DC)
335
+ {
336
+ if (Z_OBJ_HT_P(object)->has_property) {
337
+ #if PHP_VERSION_ID >= 50400
338
+ return Z_OBJ_HT_P(object)->has_property(object, propname, 0, NULL TSRMLS_CC);
339
+ #else
340
+ return Z_OBJ_HT_P(object)->has_property(object, propname, 0 TSRMLS_CC);
341
+ #endif
342
+ }
343
+ return 0;
344
+ }
345
+
346
+ int TWIG_HAS_DYNAMIC_PROPERTY(zval *object, char *prop, int prop_len TSRMLS_DC)
347
+ {
348
+ if (Z_OBJ_HT_P(object)->get_properties) {
349
+ return zend_hash_quick_exists(
350
+ Z_OBJ_HT_P(object)->get_properties(object TSRMLS_CC), // the properties hash
351
+ prop, // property name
352
+ prop_len + 1, // property length
353
+ zend_get_hash_value(prop, prop_len + 1) // hash value
354
+ );
355
+ }
356
+ return 0;
357
+ }
358
+
359
+ zval *TWIG_PROPERTY_CHAR(zval *object, char *propname TSRMLS_DC)
360
+ {
361
+ zval *tmp_name_zval, *tmp;
362
+
363
+ ALLOC_INIT_ZVAL(tmp_name_zval);
364
+ ZVAL_STRING(tmp_name_zval, propname, 1);
365
+ tmp = TWIG_PROPERTY(object, tmp_name_zval TSRMLS_CC);
366
+ FREE_DTOR(tmp_name_zval);
367
+ return tmp;
368
+ }
369
+
370
+ int TWIG_CALL_B_0(zval *object, char *method)
371
+ {
372
+ return 0;
373
+ }
374
+
375
+ zval *TWIG_CALL_S(zval *object, char *method, char *arg0 TSRMLS_DC)
376
+ {
377
+ zend_fcall_info fci;
378
+ zval **args[1];
379
+ zval *argument;
380
+ zval *zfunction;
381
+ zval *retval_ptr;
382
+
383
+ MAKE_STD_ZVAL(argument);
384
+ ZVAL_STRING(argument, arg0, 1);
385
+ args[0] = &argument;
386
+
387
+ MAKE_STD_ZVAL(zfunction);
388
+ ZVAL_STRING(zfunction, method, 1);
389
+ fci.size = sizeof(fci);
390
+ fci.function_table = EG(function_table);
391
+ fci.function_name = zfunction;
392
+ fci.symbol_table = NULL;
393
+ #if PHP_VERSION_ID >= 50300
394
+ fci.object_ptr = object;
395
+ #else
396
+ fci.object_pp = &object;
397
+ #endif
398
+ fci.retval_ptr_ptr = &retval_ptr;
399
+ fci.param_count = 1;
400
+ fci.params = args;
401
+ fci.no_separation = 0;
402
+
403
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
404
+ FREE_DTOR(zfunction);
405
+ zval_ptr_dtor(&argument);
406
+ return 0;
407
+ }
408
+ FREE_DTOR(zfunction);
409
+ zval_ptr_dtor(&argument);
410
+ return retval_ptr;
411
+ }
412
+
413
+ int TWIG_CALL_SB(zval *object, char *method, char *arg0 TSRMLS_DC)
414
+ {
415
+ zval *retval_ptr;
416
+ int success;
417
+
418
+ retval_ptr = TWIG_CALL_S(object, method, arg0 TSRMLS_CC);
419
+ success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
420
+
421
+ if (retval_ptr) {
422
+ zval_ptr_dtor(&retval_ptr);
423
+ }
424
+
425
+ return success;
426
+ }
427
+
428
+ int TWIG_CALL_Z(zval *object, char *method, zval *arg1 TSRMLS_DC)
429
+ {
430
+ zend_fcall_info fci;
431
+ zval **args[1];
432
+ zval *zfunction;
433
+ zval *retval_ptr;
434
+ int success;
435
+
436
+ args[0] = &arg1;
437
+
438
+ MAKE_STD_ZVAL(zfunction);
439
+ ZVAL_STRING(zfunction, method, 1);
440
+ fci.size = sizeof(fci);
441
+ fci.function_table = EG(function_table);
442
+ fci.function_name = zfunction;
443
+ fci.symbol_table = NULL;
444
+ #if PHP_VERSION_ID >= 50300
445
+ fci.object_ptr = object;
446
+ #else
447
+ fci.object_pp = &object;
448
+ #endif
449
+ fci.retval_ptr_ptr = &retval_ptr;
450
+ fci.param_count = 1;
451
+ fci.params = args;
452
+ fci.no_separation = 0;
453
+
454
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
455
+ FREE_DTOR(zfunction);
456
+ if (retval_ptr) {
457
+ zval_ptr_dtor(&retval_ptr);
458
+ }
459
+ return 0;
460
+ }
461
+
462
+ FREE_DTOR(zfunction);
463
+
464
+ success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
465
+ if (retval_ptr) {
466
+ zval_ptr_dtor(&retval_ptr);
467
+ }
468
+
469
+ return success;
470
+ }
471
+
472
+ int TWIG_CALL_ZZ(zval *object, char *method, zval *arg1, zval *arg2 TSRMLS_DC)
473
+ {
474
+ zend_fcall_info fci;
475
+ zval **args[2];
476
+ zval *zfunction;
477
+ zval *retval_ptr;
478
+ int success;
479
+
480
+ args[0] = &arg1;
481
+ args[1] = &arg2;
482
+
483
+ MAKE_STD_ZVAL(zfunction);
484
+ ZVAL_STRING(zfunction, method, 1);
485
+ fci.size = sizeof(fci);
486
+ fci.function_table = EG(function_table);
487
+ fci.function_name = zfunction;
488
+ fci.symbol_table = NULL;
489
+ #if PHP_VERSION_ID >= 50300
490
+ fci.object_ptr = object;
491
+ #else
492
+ fci.object_pp = &object;
493
+ #endif
494
+ fci.retval_ptr_ptr = &retval_ptr;
495
+ fci.param_count = 2;
496
+ fci.params = args;
497
+ fci.no_separation = 0;
498
+
499
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
500
+ FREE_DTOR(zfunction);
501
+ return 0;
502
+ }
503
+
504
+ FREE_DTOR(zfunction);
505
+
506
+ success = (retval_ptr && (Z_TYPE_P(retval_ptr) == IS_BOOL) && Z_LVAL_P(retval_ptr));
507
+ if (retval_ptr) {
508
+ zval_ptr_dtor(&retval_ptr);
509
+ }
510
+
511
+ return success;
512
+ }
513
+
514
+ #ifndef Z_SET_REFCOUNT_P
515
+ # define Z_SET_REFCOUNT_P(pz, rc) pz->refcount = rc
516
+ # define Z_UNSET_ISREF_P(pz) pz->is_ref = 0
517
+ #endif
518
+
519
+ void TWIG_NEW(zval *object, char *class, zval *arg0, zval *arg1 TSRMLS_DC)
520
+ {
521
+ zend_class_entry **pce;
522
+
523
+ if (zend_lookup_class(class, strlen(class), &pce TSRMLS_CC) == FAILURE) {
524
+ return;
525
+ }
526
+
527
+ Z_TYPE_P(object) = IS_OBJECT;
528
+ object_init_ex(object, *pce);
529
+ Z_SET_REFCOUNT_P(object, 1);
530
+ Z_UNSET_ISREF_P(object);
531
+
532
+ TWIG_CALL_ZZ(object, "__construct", arg0, arg1 TSRMLS_CC);
533
+ }
534
+
535
+ static int twig_add_array_key_to_string(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
536
+ {
537
+ smart_str *buf;
538
+ char *joiner;
539
+ APPLY_TSRMLS_FETCH();
540
+
541
+ buf = va_arg(args, smart_str*);
542
+ joiner = va_arg(args, char*);
543
+
544
+ if (buf->len != 0) {
545
+ smart_str_appends(buf, joiner);
546
+ }
547
+
548
+ if (hash_key->nKeyLength == 0) {
549
+ smart_str_append_long(buf, (long) hash_key->h);
550
+ } else {
551
+ char *key, *tmp_str;
552
+ int key_len, tmp_len;
553
+ key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC);
554
+ tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL);
555
+
556
+ smart_str_appendl(buf, tmp_str, tmp_len);
557
+ efree(key);
558
+ efree(tmp_str);
559
+ }
560
+
561
+ return 0;
562
+ }
563
+
564
+ char *TWIG_IMPLODE_ARRAY_KEYS(char *joiner, zval *array TSRMLS_DC)
565
+ {
566
+ smart_str collector = { 0, 0, 0 };
567
+
568
+ smart_str_appendl(&collector, "", 0);
569
+ zend_hash_apply_with_arguments(HASH_OF(array) APPLY_TSRMLS_CC, twig_add_array_key_to_string, 2, &collector, joiner);
570
+ smart_str_0(&collector);
571
+
572
+ return collector.c;
573
+ }
574
+
575
+ static void TWIG_THROW_EXCEPTION(char *exception_name TSRMLS_DC, char *message, ...)
576
+ {
577
+ char *buffer;
578
+ va_list args;
579
+ zend_class_entry **pce;
580
+
581
+ if (zend_lookup_class(exception_name, strlen(exception_name), &pce TSRMLS_CC) == FAILURE) {
582
+ return;
583
+ }
584
+
585
+ va_start(args, message);
586
+ vspprintf(&buffer, 0, message, args);
587
+ va_end(args);
588
+
589
+ zend_throw_exception_ex(*pce, 0 TSRMLS_CC, buffer);
590
+ efree(buffer);
591
+ }
592
+
593
+ static void TWIG_RUNTIME_ERROR(zval *template TSRMLS_DC, char *message, ...)
594
+ {
595
+ char *buffer;
596
+ va_list args;
597
+ zend_class_entry **pce;
598
+ zval *ex;
599
+ zval *constructor;
600
+ zval *zmessage;
601
+ zval *lineno;
602
+ zval *filename_func;
603
+ zval *filename;
604
+ zval *constructor_args[3];
605
+ zval *constructor_retval;
606
+
607
+ if (zend_lookup_class("Twig_Error_Runtime", strlen("Twig_Error_Runtime"), &pce TSRMLS_CC) == FAILURE) {
608
+ return;
609
+ }
610
+
611
+ va_start(args, message);
612
+ vspprintf(&buffer, 0, message, args);
613
+ va_end(args);
614
+
615
+ MAKE_STD_ZVAL(ex);
616
+ object_init_ex(ex, *pce);
617
+
618
+ // Call Twig_Error constructor
619
+ MAKE_STD_ZVAL(constructor);
620
+ MAKE_STD_ZVAL(zmessage);
621
+ MAKE_STD_ZVAL(lineno);
622
+ MAKE_STD_ZVAL(filename);
623
+ MAKE_STD_ZVAL(filename_func);
624
+ MAKE_STD_ZVAL(constructor_retval);
625
+
626
+ ZVAL_STRINGL(constructor, "__construct", sizeof("__construct")-1, 1);
627
+ ZVAL_STRING(zmessage, buffer, 1);
628
+ ZVAL_LONG(lineno, -1);
629
+
630
+ // Get template filename
631
+ ZVAL_STRINGL(filename_func, "getTemplateName", sizeof("getTemplateName")-1, 1);
632
+ call_user_function(EG(function_table), &template, filename_func, filename, 0, 0 TSRMLS_CC);
633
+
634
+ constructor_args[0] = zmessage;
635
+ constructor_args[1] = lineno;
636
+ constructor_args[2] = filename;
637
+ call_user_function(EG(function_table), &ex, constructor, constructor_retval, 3, constructor_args TSRMLS_CC);
638
+
639
+ zval_ptr_dtor(&constructor_retval);
640
+ zval_ptr_dtor(&zmessage);
641
+ zval_ptr_dtor(&lineno);
642
+ zval_ptr_dtor(&filename);
643
+ FREE_DTOR(constructor);
644
+ FREE_DTOR(filename_func);
645
+ efree(buffer);
646
+
647
+ zend_throw_exception_object(ex TSRMLS_CC);
648
+ }
649
+
650
+ static char *TWIG_GET_CLASS_NAME(zval *object TSRMLS_DC)
651
+ {
652
+ char *class_name;
653
+ zend_uint class_name_len;
654
+
655
+ if (Z_TYPE_P(object) != IS_OBJECT) {
656
+ return "";
657
+ }
658
+ #if PHP_API_VERSION >= 20100412
659
+ zend_get_object_classname(object, (const char **) &class_name, &class_name_len TSRMLS_CC);
660
+ #else
661
+ zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC);
662
+ #endif
663
+ return class_name;
664
+ }
665
+
666
+ static int twig_add_method_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
667
+ {
668
+ zval *retval;
669
+ char *item;
670
+ size_t item_len;
671
+ zend_function *mptr = (zend_function *) pDest;
672
+ APPLY_TSRMLS_FETCH();
673
+
674
+ if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
675
+ return 0;
676
+ }
677
+
678
+ retval = va_arg(args, zval*);
679
+
680
+ item_len = strlen(mptr->common.function_name);
681
+ item = estrndup(mptr->common.function_name, item_len);
682
+ php_strtolower(item, item_len);
683
+
684
+ add_assoc_stringl_ex(retval, item, item_len+1, item, item_len, 0);
685
+
686
+ return 0;
687
+ }
688
+
689
+ static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
690
+ {
691
+ zend_class_entry *ce;
692
+ zval *retval;
693
+ char *class_name, *prop_name;
694
+ zend_property_info *pptr = (zend_property_info *) pDest;
695
+ APPLY_TSRMLS_FETCH();
696
+
697
+ if (!(pptr->flags & ZEND_ACC_PUBLIC) || (pptr->flags & ZEND_ACC_STATIC)) {
698
+ return 0;
699
+ }
700
+
701
+ ce = *va_arg(args, zend_class_entry**);
702
+ retval = va_arg(args, zval*);
703
+
704
+ #if PHP_API_VERSION >= 20100412
705
+ zend_unmangle_property_name(pptr->name, pptr->name_length, (const char **) &class_name, (const char **) &prop_name);
706
+ #else
707
+ zend_unmangle_property_name(pptr->name, pptr->name_length, &class_name, &prop_name);
708
+ #endif
709
+
710
+ add_assoc_string(retval, prop_name, prop_name, 1);
711
+
712
+ return 0;
713
+ }
714
+
715
+ static void twig_add_class_to_cache(zval *cache, zval *object, char *class_name TSRMLS_DC)
716
+ {
717
+ zval *class_info, *class_methods, *class_properties;
718
+ zend_class_entry *class_ce;
719
+
720
+ class_ce = zend_get_class_entry(object TSRMLS_CC);
721
+
722
+ ALLOC_INIT_ZVAL(class_info);
723
+ ALLOC_INIT_ZVAL(class_methods);
724
+ ALLOC_INIT_ZVAL(class_properties);
725
+ array_init(class_info);
726
+ array_init(class_methods);
727
+ array_init(class_properties);
728
+ // add all methods to self::cache[$class]['methods']
729
+ zend_hash_apply_with_arguments(&class_ce->function_table APPLY_TSRMLS_CC, twig_add_method_to_class, 1, class_methods);
730
+ zend_hash_apply_with_arguments(&class_ce->properties_info APPLY_TSRMLS_CC, twig_add_property_to_class, 2, &class_ce, class_properties);
731
+
732
+ add_assoc_zval(class_info, "methods", class_methods);
733
+ add_assoc_zval(class_info, "properties", class_properties);
734
+ add_assoc_zval(cache, class_name, class_info);
735
+ }
736
+
737
+ /* {{{ proto mixed twig_template_get_attributes(TwigTemplate template, mixed object, mixed item, array arguments, string type, boolean isDefinedTest, boolean ignoreStrictCheck)
738
+ A C implementation of TwigTemplate::getAttribute() */
739
+ PHP_FUNCTION(twig_template_get_attributes)
740
+ {
741
+ zval *template;
742
+ zval *object;
743
+ char *item;
744
+ int item_len;
745
+ zval *zitem, ztmpitem;
746
+ zval *arguments = NULL;
747
+ zval *ret = NULL;
748
+ char *type = NULL;
749
+ int type_len = 0;
750
+ zend_bool isDefinedTest = 0;
751
+ zend_bool ignoreStrictCheck = 0;
752
+ int free_ret = 0;
753
+ zval *tmp_self_cache;
754
+ char *class_name = NULL;
755
+ zval *tmp_class;
756
+ char *type_name;
757
+
758
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) {
759
+ return;
760
+ }
761
+
762
+ // convert the item to a string
763
+ ztmpitem = *zitem;
764
+ zval_copy_ctor(&ztmpitem);
765
+ convert_to_string(&ztmpitem);
766
+ item_len = Z_STRLEN(ztmpitem);
767
+ item = estrndup(Z_STRVAL(ztmpitem), item_len);
768
+ zval_dtor(&ztmpitem);
769
+
770
+ if (!type) {
771
+ type = "any";
772
+ }
773
+
774
+ /*
775
+ // array
776
+ if (Twig_Template::METHOD_CALL !== $type) {
777
+ $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
778
+
779
+ if ((is_array($object) && array_key_exists($arrayItem, $object))
780
+ || ($object instanceof ArrayAccess && isset($object[$arrayItem]))
781
+ ) {
782
+ if ($isDefinedTest) {
783
+ return true;
784
+ }
785
+
786
+ return $object[$arrayItem];
787
+ }
788
+ */
789
+
790
+
791
+ if (strcmp("method", type) != 0) {
792
+ if ((TWIG_ARRAY_KEY_EXISTS(object, zitem))
793
+ || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC))
794
+ ) {
795
+
796
+ if (isDefinedTest) {
797
+ RETURN_TRUE;
798
+ }
799
+
800
+ ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC);
801
+
802
+ if (!ret) {
803
+ ret = &EG(uninitialized_zval);
804
+ }
805
+ RETVAL_ZVAL(ret, 1, 0);
806
+ if (free_ret) {
807
+ zval_ptr_dtor(&ret);
808
+ }
809
+ return;
810
+ }
811
+ /*
812
+ if (Twig_Template::ARRAY_CALL === $type) {
813
+ if ($isDefinedTest) {
814
+ return false;
815
+ }
816
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
817
+ return null;
818
+ }
819
+ */
820
+ if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
821
+ if (isDefinedTest) {
822
+ RETURN_FALSE;
823
+ }
824
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
825
+ return;
826
+ }
827
+ /*
828
+ if ($object instanceof ArrayAccess) {
829
+ $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object));
830
+ } elseif (is_object($object)) {
831
+ $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
832
+ } elseif (is_array($object)) {
833
+ $message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
834
+ } elseif (Twig_Template::ARRAY_CALL === $type) {
835
+ $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
836
+ } else {
837
+ $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
838
+ }
839
+ throw new Twig_Error_Runtime($message, -1, $this->getTemplateName());
840
+ }
841
+ }
842
+ */
843
+ if (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC)) {
844
+ 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));
845
+ } else if (Z_TYPE_P(object) == IS_OBJECT) {
846
+ 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));
847
+ } else if (Z_TYPE_P(object) == IS_ARRAY) {
848
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
849
+ } else {
850
+ char *type_name = zend_zval_type_name(object);
851
+ Z_ADDREF_P(object);
852
+ convert_to_string(object);
853
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC,
854
+ (strcmp("array", type) == 0)
855
+ ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
856
+ : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
857
+ item, type_name, Z_STRVAL_P(object));
858
+ zval_ptr_dtor(&object);
859
+ }
860
+ return;
861
+ }
862
+ }
863
+
864
+ /*
865
+ if (!is_object($object)) {
866
+ if ($isDefinedTest) {
867
+ return false;
868
+ }
869
+ */
870
+
871
+ if (Z_TYPE_P(object) != IS_OBJECT) {
872
+ if (isDefinedTest) {
873
+ RETURN_FALSE;
874
+ }
875
+ /*
876
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
877
+ return null;
878
+ }
879
+ throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
880
+ }
881
+ */
882
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
883
+ return;
884
+ }
885
+
886
+ type_name = zend_zval_type_name(object);
887
+ Z_ADDREF_P(object);
888
+ convert_to_string_ex(&object);
889
+
890
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
891
+
892
+ zval_ptr_dtor(&object);
893
+
894
+ return;
895
+ }
896
+ /*
897
+ $class = get_class($object);
898
+ */
899
+
900
+ class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
901
+ tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC);
902
+ tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
903
+
904
+ if (!tmp_class) {
905
+ twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC);
906
+ tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
907
+ }
908
+ efree(class_name);
909
+
910
+ /*
911
+ // object property
912
+ if (Twig_Template::METHOD_CALL !== $type) {
913
+ if (isset($object->$item) || array_key_exists((string) $item, $object)) {
914
+ if ($isDefinedTest) {
915
+ return true;
916
+ }
917
+
918
+ if ($this->env->hasExtension('sandbox')) {
919
+ $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
920
+ }
921
+
922
+ return $object->$item;
923
+ }
924
+ }
925
+ */
926
+ if (strcmp("method", type) != 0) {
927
+ zval *tmp_properties, *tmp_item;
928
+
929
+ tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
930
+ tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC);
931
+
932
+ if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
933
+ if (isDefinedTest) {
934
+ RETURN_TRUE;
935
+ }
936
+ if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
937
+ TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
938
+ }
939
+ if (EG(exception)) {
940
+ return;
941
+ }
942
+
943
+ ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
944
+ RETURN_ZVAL(ret, 1, 0);
945
+ }
946
+ }
947
+ /*
948
+ // object method
949
+ if (!isset(self::$cache[$class]['methods'])) {
950
+ self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
951
+ }
952
+
953
+ $call = false;
954
+ $lcItem = strtolower($item);
955
+ if (isset(self::$cache[$class]['methods'][$lcItem])) {
956
+ $method = (string) $item;
957
+ } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
958
+ $method = 'get'.$item;
959
+ } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
960
+ $method = 'is'.$item;
961
+ } elseif (isset(self::$cache[$class]['methods']['__call'])) {
962
+ $method = (string) $item;
963
+ $call = true;
964
+ */
965
+ {
966
+ int call = 0;
967
+ char *lcItem = TWIG_STRTOLOWER(item, item_len);
968
+ int lcItem_length;
969
+ char *method = NULL;
970
+ char *tmp_method_name_get;
971
+ char *tmp_method_name_is;
972
+ zval *zmethod;
973
+ zval *tmp_methods;
974
+
975
+ lcItem_length = strlen(lcItem);
976
+ tmp_method_name_get = emalloc(4 + lcItem_length);
977
+ tmp_method_name_is = emalloc(3 + lcItem_length);
978
+
979
+ sprintf(tmp_method_name_get, "get%s", lcItem);
980
+ sprintf(tmp_method_name_is, "is%s", lcItem);
981
+
982
+ tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC);
983
+
984
+ if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) {
985
+ method = item;
986
+ } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_get, lcItem_length + 3 TSRMLS_CC)) {
987
+ method = tmp_method_name_get;
988
+ } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, tmp_method_name_is, lcItem_length + 2 TSRMLS_CC)) {
989
+ method = tmp_method_name_is;
990
+ } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) {
991
+ method = item;
992
+ call = 1;
993
+ /*
994
+ } else {
995
+ if ($isDefinedTest) {
996
+ return false;
997
+ }
998
+
999
+ if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
1000
+ return null;
1001
+ }
1002
+
1003
+ throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
1004
+ }
1005
+
1006
+ if ($isDefinedTest) {
1007
+ return true;
1008
+ }
1009
+ */
1010
+ } else {
1011
+ efree(tmp_method_name_get);
1012
+ efree(tmp_method_name_is);
1013
+ efree(lcItem);
1014
+
1015
+ if (isDefinedTest) {
1016
+ RETURN_FALSE;
1017
+ }
1018
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
1019
+ return;
1020
+ }
1021
+ TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Method \"%s\" for object \"%s\" does not exist", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
1022
+ return;
1023
+ }
1024
+
1025
+ if (isDefinedTest) {
1026
+ efree(tmp_method_name_get);
1027
+ efree(tmp_method_name_is);
1028
+ efree(lcItem);
1029
+ RETURN_TRUE;
1030
+ }
1031
+ /*
1032
+ if ($this->env->hasExtension('sandbox')) {
1033
+ $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
1034
+ }
1035
+ */
1036
+ MAKE_STD_ZVAL(zmethod);
1037
+ ZVAL_STRING(zmethod, method, 1);
1038
+ if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
1039
+ TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zmethod TSRMLS_CC);
1040
+ }
1041
+ if (EG(exception)) {
1042
+ efree(tmp_method_name_get);
1043
+ efree(tmp_method_name_is);
1044
+ efree(lcItem);
1045
+ zval_ptr_dtor(&zmethod);
1046
+ return;
1047
+ }
1048
+ /*
1049
+ // Some objects throw exceptions when they have __call, and the method we try
1050
+ // to call is not supported. If ignoreStrictCheck is true, we should return null.
1051
+ try {
1052
+ $ret = call_user_func_array(array($object, $method), $arguments);
1053
+ } catch (BadMethodCallException $e) {
1054
+ if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
1055
+ return null;
1056
+ }
1057
+ throw $e;
1058
+ }
1059
+ */
1060
+ ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
1061
+ if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) {
1062
+ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
1063
+ zend_clear_exception(TSRMLS_C);
1064
+ return;
1065
+ }
1066
+ }
1067
+ free_ret = 1;
1068
+ efree(tmp_method_name_get);
1069
+ efree(tmp_method_name_is);
1070
+ efree(lcItem);
1071
+ zval_ptr_dtor(&zmethod);
1072
+ }
1073
+ /*
1074
+ // useful when calling a template method from a template
1075
+ // this is not supported but unfortunately heavily used in the Symfony profiler
1076
+ if ($object instanceof Twig_TemplateInterface) {
1077
+ return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
1078
+ }
1079
+
1080
+ return $ret;
1081
+ */
1082
+ // ret can be null, if e.g. the called method throws an exception
1083
+ if (ret) {
1084
+ if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
1085
+ if (Z_STRLEN_P(ret) != 0) {
1086
+ zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC);
1087
+ TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC);
1088
+ zval_ptr_dtor(&charset);
1089
+ if (ret) {
1090
+ zval_ptr_dtor(&ret);
1091
+ }
1092
+ return;
1093
+ }
1094
+ }
1095
+
1096
+ RETVAL_ZVAL(ret, 1, 0);
1097
+ if (free_ret) {
1098
+ zval_ptr_dtor(&ret);
1099
+ }
1100
+ }
1101
+ }
vendor/vendor/twig/twig/lib/Twig/Autoloader.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Autoloads Twig classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Autoloader
18
+ {
19
+ /**
20
+ * Registers Twig_Autoloader as an SPL autoloader.
21
+ *
22
+ * @param Boolean $prepend Whether to prepend the autoloader or not.
23
+ */
24
+ public static function register($prepend = false)
25
+ {
26
+ if (version_compare(phpversion(), '5.3.0', '>=')) {
27
+ spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend);
28
+ } else {
29
+ spl_autoload_register(array(__CLASS__, 'autoload'));
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Handles autoloading of classes.
35
+ *
36
+ * @param string $class A class name.
37
+ */
38
+ public static function autoload($class)
39
+ {
40
+ if (0 !== strpos($class, 'Twig')) {
41
+ return;
42
+ }
43
+
44
+ if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
45
+ require $file;
46
+ }
47
+ }
48
+ }
vendor/vendor/twig/twig/lib/Twig/Compiler.php ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Compiles a node to PHP code.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Compiler implements Twig_CompilerInterface
19
+ {
20
+ protected $lastLine;
21
+ protected $source;
22
+ protected $indentation;
23
+ protected $env;
24
+ protected $debugInfo;
25
+ protected $sourceOffset;
26
+ protected $sourceLine;
27
+ protected $filename;
28
+
29
+ /**
30
+ * Constructor.
31
+ *
32
+ * @param Twig_Environment $env The twig environment instance
33
+ */
34
+ public function __construct(Twig_Environment $env)
35
+ {
36
+ $this->env = $env;
37
+ $this->debugInfo = array();
38
+ }
39
+
40
+ public function getFilename()
41
+ {
42
+ return $this->filename;
43
+ }
44
+
45
+ /**
46
+ * Returns the environment instance related to this compiler.
47
+ *
48
+ * @return Twig_Environment The environment instance
49
+ */
50
+ public function getEnvironment()
51
+ {
52
+ return $this->env;
53
+ }
54
+
55
+ /**
56
+ * Gets the current PHP code after compilation.
57
+ *
58
+ * @return string The PHP code
59
+ */
60
+ public function getSource()
61
+ {
62
+ return $this->source;
63
+ }
64
+
65
+ /**
66
+ * Compiles a node.
67
+ *
68
+ * @param Twig_NodeInterface $node The node to compile
69
+ * @param integer $indentation The current indentation
70
+ *
71
+ * @return Twig_Compiler The current compiler instance
72
+ */
73
+ public function compile(Twig_NodeInterface $node, $indentation = 0)
74
+ {
75
+ $this->lastLine = null;
76
+ $this->source = '';
77
+ $this->sourceOffset = 0;
78
+ // source code starts at 1 (as we then increment it when we encounter new lines)
79
+ $this->sourceLine = 1;
80
+ $this->indentation = $indentation;
81
+
82
+ if ($node instanceof Twig_Node_Module) {
83
+ $this->filename = $node->getAttribute('filename');
84
+ }
85
+
86
+ $node->compile($this);
87
+
88
+ return $this;
89
+ }
90
+
91
+ public function subcompile(Twig_NodeInterface $node, $raw = true)
92
+ {
93
+ if (false === $raw) {
94
+ $this->addIndentation();
95
+ }
96
+
97
+ $node->compile($this);
98
+
99
+ return $this;
100
+ }
101
+
102
+ /**
103
+ * Adds a raw string to the compiled code.
104
+ *
105
+ * @param string $string The string
106
+ *
107
+ * @return Twig_Compiler The current compiler instance
108
+ */
109
+ public function raw($string)
110
+ {
111
+ $this->source .= $string;
112
+
113
+ return $this;
114
+ }
115
+
116
+ /**
117
+ * Writes a string to the compiled code by adding indentation.
118
+ *
119
+ * @return Twig_Compiler The current compiler instance
120
+ */
121
+ public function write()
122
+ {
123
+ $strings = func_get_args();
124
+ foreach ($strings as $string) {
125
+ $this->addIndentation();
126
+ $this->source .= $string;
127
+ }
128
+
129
+ return $this;
130
+ }
131
+
132
+ /**
133
+ * Appends an indentation to the current PHP code after compilation.
134
+ *
135
+ * @return Twig_Compiler The current compiler instance
136
+ */
137
+ public function addIndentation()
138
+ {
139
+ $this->source .= str_repeat(' ', $this->indentation * 4);
140
+
141
+ return $this;
142
+ }
143
+
144
+ /**
145
+ * Adds a quoted string to the compiled code.
146
+ *
147
+ * @param string $value The string
148
+ *
149
+ * @return Twig_Compiler The current compiler instance
150
+ */
151
+ public function string($value)
152
+ {
153
+ $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
154
+
155
+ return $this;
156
+ }
157
+
158
+ /**
159
+ * Returns a PHP representation of a given value.
160
+ *
161
+ * @param mixed $value The value to convert
162
+ *
163
+ * @return Twig_Compiler The current compiler instance
164
+ */
165
+ public function repr($value)
166
+ {
167
+ if (is_int($value) || is_float($value)) {
168
+ if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
169
+ setlocale(LC_NUMERIC, 'C');
170
+ }
171
+
172
+ $this->raw($value);
173
+
174
+ if (false !== $locale) {
175
+ setlocale(LC_NUMERIC, $locale);
176
+ }
177
+ } elseif (null === $value) {
178
+ $this->raw('null');
179
+ } elseif (is_bool($value)) {
180
+ $this->raw($value ? 'true' : 'false');
181
+ } elseif (is_array($value)) {
182
+ $this->raw('array(');
183
+ $first = true;
184
+ foreach ($value as $key => $value) {
185
+ if (!$first) {
186
+ $this->raw(', ');
187
+ }
188
+ $first = false;
189
+ $this->repr($key);
190
+ $this->raw(' => ');
191
+ $this->repr($value);
192
+ }
193
+ $this->raw(')');
194
+ } else {
195
+ $this->string($value);
196
+ }
197
+
198
+ return $this;
199
+ }
200
+
201
+ /**
202
+ * Adds debugging information.
203
+ *
204
+ * @param Twig_NodeInterface $node The related twig node
205
+ *
206
+ * @return Twig_Compiler The current compiler instance
207
+ */
208
+ public function addDebugInfo(Twig_NodeInterface $node)
209
+ {
210
+ if ($node->getLine() != $this->lastLine) {
211
+ $this->write(sprintf("// line %d\n", $node->getLine()));
212
+
213
+ // when mbstring.func_overload is set to 2
214
+ // mb_substr_count() replaces substr_count()
215
+ // but they have different signatures!
216
+ if (((int) ini_get('mbstring.func_overload')) & 2) {
217
+ // this is much slower than the "right" version
218
+ $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
219
+ } else {
220
+ $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
221
+ }
222
+ $this->sourceOffset = strlen($this->source);
223
+ $this->debugInfo[$this->sourceLine] = $node->getLine();
224
+
225
+ $this->lastLine = $node->getLine();
226
+ }
227
+
228
+ return $this;
229
+ }
230
+
231
+ public function getDebugInfo()
232
+ {
233
+ return $this->debugInfo;
234
+ }
235
+
236
+ /**
237
+ * Indents the generated code.
238
+ *
239
+ * @param integer $step The number of indentation to add
240
+ *
241
+ * @return Twig_Compiler The current compiler instance
242
+ */
243
+ public function indent($step = 1)
244
+ {
245
+ $this->indentation += $step;
246
+
247
+ return $this;
248
+ }
249
+
250
+ /**
251
+ * Outdents the generated code.
252
+ *
253
+ * @param integer $step The number of indentation to remove
254
+ *
255
+ * @return Twig_Compiler The current compiler instance
256
+ *
257
+ * @throws LogicException When trying to outdent too much so the indentation would become negative
258
+ */
259
+ public function outdent($step = 1)
260
+ {
261
+ // can't outdent by more steps than the current indentation level
262
+ if ($this->indentation < $step) {
263
+ throw new LogicException('Unable to call outdent() as the indentation would become negative');
264
+ }
265
+
266
+ $this->indentation -= $step;
267
+
268
+ return $this;
269
+ }
270
+ }
vendor/vendor/twig/twig/lib/Twig/CompilerInterface.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by compiler classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ * @deprecated since 1.12 (to be removed in 2.0)
17
+ */
18
+ interface Twig_CompilerInterface
19
+ {
20
+ /**
21
+ * Compiles a node.
22
+ *
23
+ * @param Twig_NodeInterface $node The node to compile
24
+ *
25
+ * @return Twig_CompilerInterface The current compiler instance
26
+ */
27
+ public function compile(Twig_NodeInterface $node);
28
+
29
+ /**
30
+ * Gets the current PHP code after compilation.
31
+ *
32
+ * @return string The PHP code
33
+ */
34
+ public function getSource();
35
+ }
vendor/vendor/twig/twig/lib/Twig/Environment.php ADDED
@@ -0,0 +1,1254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Stores the Twig configuration.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Environment
18
+ {
19
+ const VERSION = '1.15.1';
20
+
21
+ protected $charset;
22
+ protected $loader;
23
+ protected $debug;
24
+ protected $autoReload;
25
+ protected $cache;
26
+ protected $lexer;
27
+ protected $parser;
28
+ protected $compiler;
29
+ protected $baseTemplateClass;
30
+ protected $extensions;
31
+ protected $parsers;
32
+ protected $visitors;
33
+ protected $filters;
34
+ protected $tests;
35
+ protected $functions;
36
+ protected $globals;
37
+ protected $runtimeInitialized;
38
+ protected $extensionInitialized;
39
+ protected $loadedTemplates;
40
+ protected $strictVariables;
41
+ protected $unaryOperators;
42
+ protected $binaryOperators;
43
+ protected $templateClassPrefix = '__TwigTemplate_';
44
+ protected $functionCallbacks;
45
+ protected $filterCallbacks;
46
+ protected $staging;
47
+
48
+ /**
49
+ * Constructor.
50
+ *
51
+ * Available options:
52
+ *
53
+ * * debug: When set to true, it automatically set "auto_reload" to true as
54
+ * well (default to false).
55
+ *
56
+ * * charset: The charset used by the templates (default to UTF-8).
57
+ *
58
+ * * base_template_class: The base template class to use for generated
59
+ * templates (default to Twig_Template).
60
+ *
61
+ * * cache: An absolute path where to store the compiled templates, or
62
+ * false to disable compilation cache (default).
63
+ *
64
+ * * auto_reload: Whether to reload the template if the original source changed.
65
+ * If you don't provide the auto_reload option, it will be
66
+ * determined automatically based on the debug value.
67
+ *
68
+ * * strict_variables: Whether to ignore invalid variables in templates
69
+ * (default to false).
70
+ *
71
+ * * autoescape: Whether to enable auto-escaping (default to html):
72
+ * * false: disable auto-escaping
73
+ * * true: equivalent to html
74
+ * * html, js: set the autoescaping to one of the supported strategies
75
+ * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
76
+ *
77
+ * * optimizations: A flag that indicates which optimizations to apply
78
+ * (default to -1 which means that all optimizations are enabled;
79
+ * set it to 0 to disable).
80
+ *
81
+ * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
82
+ * @param array $options An array of options
83
+ */
84
+ public function __construct(Twig_LoaderInterface $loader = null, $options = array())
85
+ {
86
+ if (null !== $loader) {
87
+ $this->setLoader($loader);
88
+ }
89
+
90
+ $options = array_merge(array(
91
+ 'debug' => false,
92
+ 'charset' => 'UTF-8',
93
+ 'base_template_class' => 'Twig_Template',
94
+ 'strict_variables' => false,
95
+ 'autoescape' => 'html',
96
+ 'cache' => false,
97
+ 'auto_reload' => null,
98
+ 'optimizations' => -1,
99
+ ), $options);
100
+
101
+ $this->debug = (bool) $options['debug'];
102
+ $this->charset = strtoupper($options['charset']);
103
+ $this->baseTemplateClass = $options['base_template_class'];
104
+ $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
105
+ $this->strictVariables = (bool) $options['strict_variables'];
106
+ $this->runtimeInitialized = false;
107
+ $this->setCache($options['cache']);
108
+ $this->functionCallbacks = array();
109
+ $this->filterCallbacks = array();
110
+
111
+ $this->addExtension(new Twig_Extension_Core());
112
+ $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
113
+ $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
114
+ $this->extensionInitialized = false;
115
+ $this->staging = new Twig_Extension_Staging();
116
+ }
117
+
118
+ /**
119
+ * Gets the base template class for compiled templates.
120
+ *
121
+ * @return string The base template class name
122
+ */
123
+ public function getBaseTemplateClass()
124
+ {
125
+ return $this->baseTemplateClass;
126
+ }
127
+
128
+ /**
129
+ * Sets the base template class for compiled templates.
130
+ *
131
+ * @param string $class The base template class name
132
+ */
133
+ public function setBaseTemplateClass($class)
134
+ {
135
+ $this->baseTemplateClass = $class;
136
+ }
137
+
138
+ /**
139
+ * Enables debugging mode.
140
+ */
141
+ public function enableDebug()
142
+ {
143
+ $this->debug = true;
144
+ }
145
+
146
+ /**
147
+ * Disables debugging mode.
148
+ */
149
+ public function disableDebug()
150
+ {
151
+ $this->debug = false;
152
+ }
153
+
154
+ /**
155
+ * Checks if debug mode is enabled.
156
+ *
157
+ * @return Boolean true if debug mode is enabled, false otherwise
158
+ */
159
+ public function isDebug()
160
+ {
161
+ return $this->debug;
162
+ }
163
+
164
+ /**
165
+ * Enables the auto_reload option.
166
+ */
167
+ public function enableAutoReload()
168
+ {
169
+ $this->autoReload = true;
170
+ }
171
+
172
+ /**
173
+ * Disables the auto_reload option.
174
+ */
175
+ public function disableAutoReload()
176
+ {
177
+ $this->autoReload = false;
178
+ }
179
+
180
+ /**
181
+ * Checks if the auto_reload option is enabled.
182
+ *
183
+ * @return Boolean true if auto_reload is enabled, false otherwise
184
+ */
185
+ public function isAutoReload()
186
+ {
187
+ return $this->autoReload;
188
+ }
189
+
190
+ /**
191
+ * Enables the strict_variables option.
192
+ */
193
+ public function enableStrictVariables()
194
+ {
195
+ $this->strictVariables = true;
196
+ }
197
+
198
+ /**
199
+ * Disables the strict_variables option.
200
+ */
201
+ public function disableStrictVariables()
202
+ {
203
+ $this->strictVariables = false;
204
+ }
205
+
206
+ /**
207
+ * Checks if the strict_variables option is enabled.
208
+ *
209
+ * @return Boolean true if strict_variables is enabled, false otherwise
210
+ */
211
+ public function isStrictVariables()
212
+ {
213
+ return $this->strictVariables;
214
+ }
215
+
216
+ /**
217
+ * Gets the cache directory or false if cache is disabled.
218
+ *
219
+ * @return string|false
220
+ */
221
+ public function getCache()
222
+ {
223
+ return $this->cache;
224
+ }
225
+
226
+ /**
227
+ * Sets the cache directory or false if cache is disabled.
228
+ *
229
+ * @param string|false $cache The absolute path to the compiled templates,
230
+ * or false to disable cache
231
+ */
232
+ public function setCache($cache)
233
+ {
234
+ $this->cache = $cache ? $cache : false;
235
+ }
236
+
237
+ /**
238
+ * Gets the cache filename for a given template.
239
+ *
240
+ * @param string $name The template name
241
+ *
242
+ * @return string|false The cache file name or false when caching is disabled
243
+ */
244
+ public function getCacheFilename($name)
245
+ {
246
+ if (false === $this->cache) {
247
+ return false;
248
+ }
249
+
250
+ $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
251
+
252
+ return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
253
+ }
254
+
255
+ /**
256
+ * Gets the template class associated with the given string.
257
+ *
258
+ * @param string $name The name for which to calculate the template class name
259
+ * @param integer $index The index if it is an embedded template
260
+ *
261
+ * @return string The template class name
262
+ */
263
+ public function getTemplateClass($name, $index = null)
264
+ {
265
+ return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
266
+ }
267
+
268
+ /**
269
+ * Gets the template class prefix.
270
+ *
271
+ * @return string The template class prefix
272
+ */
273
+ public function getTemplateClassPrefix()
274
+ {
275
+ return $this->templateClassPrefix;
276
+ }
277
+
278
+ /**
279
+ * Renders a template.
280
+ *
281
+ * @param string $name The template name
282
+ * @param array $context An array of parameters to pass to the template
283
+ *
284
+ * @return string The rendered template
285
+ *
286
+ * @throws Twig_Error_Loader When the template cannot be found
287
+ * @throws Twig_Error_Syntax When an error occurred during compilation
288
+ * @throws Twig_Error_Runtime When an error occurred during rendering
289
+ */
290
+ public function render($name, array $context = array())
291
+ {
292
+ return $this->loadTemplate($name)->render($context);
293
+ }
294
+
295
+ /**
296
+ * Displays a template.
297
+ *
298
+ * @param string $name The template name
299
+ * @param array $context An array of parameters to pass to the template
300
+ *
301
+ * @throws Twig_Error_Loader When the template cannot be found
302
+ * @throws Twig_Error_Syntax When an error occurred during compilation
303
+ * @throws Twig_Error_Runtime When an error occurred during rendering
304
+ */
305
+ public function display($name, array $context = array())
306
+ {
307
+ $this->loadTemplate($name)->display($context);
308
+ }
309
+
310
+ /**
311
+ * Loads a template by name.
312
+ *
313
+ * @param string $name The template name
314
+ * @param integer $index The index if it is an embedded template
315
+ *
316
+ * @return Twig_TemplateInterface A template instance representing the given template name
317
+ *
318
+ * @throws Twig_Error_Loader When the template cannot be found
319
+ * @throws Twig_Error_Syntax When an error occurred during compilation
320
+ */
321
+ public function loadTemplate($name, $index = null)
322
+ {
323
+ $cls = $this->getTemplateClass($name, $index);
324
+
325
+ if (isset($this->loadedTemplates[$cls])) {
326
+ return $this->loadedTemplates[$cls];
327
+ }
328
+
329
+ if (!class_exists($cls, false)) {
330
+ if (false === $cache = $this->getCacheFilename($name)) {
331
+ eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
332
+ } else {
333
+ if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
334
+ $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
335
+ }
336
+
337
+ require_once $cache;
338
+ }
339
+ }
340
+
341
+ if (!$this->runtimeInitialized) {
342
+ $this->initRuntime();
343
+ }
344
+
345
+ return $this->loadedTemplates[$cls] = new $cls($this);
346
+ }
347
+
348
+ /**
349
+ * Returns true if the template is still fresh.
350
+ *
351
+ * Besides checking the loader for freshness information,
352
+ * this method also checks if the enabled extensions have
353
+ * not changed.
354
+ *
355
+ * @param string $name The template name
356
+ * @param timestamp $time The last modification time of the cached template
357
+ *
358
+ * @return Boolean true if the template is fresh, false otherwise
359
+ */
360
+ public function isTemplateFresh($name, $time)
361
+ {
362
+ foreach ($this->extensions as $extension) {
363
+ $r = new ReflectionObject($extension);
364
+ if (filemtime($r->getFileName()) > $time) {
365
+ return false;
366
+ }
367
+ }
368
+
369
+ return $this->getLoader()->isFresh($name, $time);
370
+ }
371
+
372
+ /**
373
+ * Tries to load a template consecutively from an array.
374
+ *
375
+ * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array
376
+ * of templates where each is tried to be loaded.
377
+ *
378
+ * @param string|Twig_Template|array $names A template or an array of templates to try consecutively
379
+ *
380
+ * @return Twig_Template
381
+ *
382
+ * @throws Twig_Error_Loader When none of the templates can be found
383
+ * @throws Twig_Error_Syntax When an error occurred during compilation
384
+ */
385
+ public function resolveTemplate($names)
386
+ {
387
+ if (!is_array($names)) {
388
+ $names = array($names);
389
+ }
390
+
391
+ foreach ($names as $name) {
392
+ if ($name instanceof Twig_Template) {
393
+ return $name;
394
+ }
395
+
396
+ try {
397
+ return $this->loadTemplate($name);
398
+ } catch (Twig_Error_Loader $e) {
399
+ }
400
+ }
401
+
402
+ if (1 === count($names)) {
403
+ throw $e;
404
+ }
405
+
406
+ throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
407
+ }
408
+
409
+ /**
410
+ * Clears the internal template cache.
411
+ */
412
+ public function clearTemplateCache()
413
+ {
414
+ $this->loadedTemplates = array();
415
+ }
416
+
417
+ /**
418
+ * Clears the template cache files on the filesystem.
419
+ */
420
+ public function clearCacheFiles()
421
+ {
422
+ if (false === $this->cache) {
423
+ return;
424
+ }
425
+
426
+ foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
427
+ if ($file->isFile()) {
428
+ @unlink($file->getPathname());
429
+ }
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Gets the Lexer instance.
435
+ *
436
+ * @return Twig_LexerInterface A Twig_LexerInterface instance
437
+ */
438
+ public function getLexer()
439
+ {
440
+ if (null === $this->lexer) {
441
+ $this->lexer = new Twig_Lexer($this);
442
+ }
443
+
444
+ return $this->lexer;
445
+ }
446
+
447
+ /**
448
+ * Sets the Lexer instance.
449
+ *
450
+ * @param Twig_LexerInterface A Twig_LexerInterface instance
451
+ */
452
+ public function setLexer(Twig_LexerInterface $lexer)
453
+ {
454
+ $this->lexer = $lexer;
455
+ }
456
+
457
+ /**
458
+ * Tokenizes a source code.
459
+ *
460
+ * @param string $source The template source code
461
+ * @param string $name The template name
462
+ *
463
+ * @return Twig_TokenStream A Twig_TokenStream instance
464
+ *
465
+ * @throws Twig_Error_Syntax When the code is syntactically wrong
466
+ */
467
+ public function tokenize($source, $name = null)
468
+ {
469
+ return $this->getLexer()->tokenize($source, $name);
470
+ }
471
+
472
+ /**
473
+ * Gets the Parser instance.
474
+ *
475
+ * @return Twig_ParserInterface A Twig_ParserInterface instance
476
+ */
477
+ public function getParser()
478
+ {
479
+ if (null === $this->parser) {
480
+ $this->parser = new Twig_Parser($this);
481
+ }
482
+
483
+ return $this->parser;
484
+ }
485
+
486
+ /**
487
+ * Sets the Parser instance.
488
+ *
489
+ * @param Twig_ParserInterface A Twig_ParserInterface instance
490
+ */
491
+ public function setParser(Twig_ParserInterface $parser)
492
+ {
493
+ $this->parser = $parser;
494
+ }
495
+
496
+ /**
497
+ * Converts a token stream to a node tree.
498
+ *
499
+ * @param Twig_TokenStream $stream A token stream instance
500
+ *
501
+ * @return Twig_Node_Module A node tree
502
+ *
503
+ * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
504
+ */
505
+ public function parse(Twig_TokenStream $stream)
506
+ {
507
+ return $this->getParser()->parse($stream);
508
+ }
509
+
510
+ /**
511
+ * Gets the Compiler instance.
512
+ *
513
+ * @return Twig_CompilerInterface A Twig_CompilerInterface instance
514
+ */
515
+ public function getCompiler()
516
+ {
517
+ if (null === $this->compiler) {
518
+ $this->compiler = new Twig_Compiler($this);
519
+ }
520
+
521
+ return $this->compiler;
522
+ }
523
+
524
+ /**
525
+ * Sets the Compiler instance.
526
+ *
527
+ * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
528
+ */
529
+ public function setCompiler(Twig_CompilerInterface $compiler)
530
+ {
531
+ $this->compiler = $compiler;
532
+ }
533
+
534
+ /**
535
+ * Compiles a node and returns the PHP code.
536
+ *
537
+ * @param Twig_NodeInterface $node A Twig_NodeInterface instance
538
+ *
539
+ * @return string The compiled PHP source code
540
+ */
541
+ public function compile(Twig_NodeInterface $node)
542
+ {
543
+ return $this->getCompiler()->compile($node)->getSource();
544
+ }
545
+
546
+ /**
547
+ * Compiles a template source code.
548
+ *
549
+ * @param string $source The template source code
550
+ * @param string $name The template name
551
+ *
552
+ * @return string The compiled PHP source code
553
+ *
554
+ * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
555
+ */
556
+ public function compileSource($source, $name = null)
557
+ {
558
+ try {
559
+ return $this->compile($this->parse($this->tokenize($source, $name)));
560
+ } catch (Twig_Error $e) {
561
+ $e->setTemplateFile($name);
562
+ throw $e;
563
+ } catch (Exception $e) {
564
+ throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
565
+ }
566
+ }
567
+
568
+ /**
569
+ * Sets the Loader instance.
570
+ *
571
+ * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
572
+ */
573
+ public function setLoader(Twig_LoaderInterface $loader)
574
+ {
575
+ $this->loader = $loader;
576
+ }
577
+
578
+ /**
579
+ * Gets the Loader instance.
580
+ *
581
+ * @return Twig_LoaderInterface A Twig_LoaderInterface instance
582
+ */
583
+ public function getLoader()
584
+ {
585
+ if (null === $this->loader) {
586
+ throw new LogicException('You must set a loader first.');
587
+ }
588
+
589
+ return $this->loader;
590
+ }
591
+
592
+ /**
593
+ * Sets the default template charset.
594
+ *
595
+ * @param string $charset The default charset
596
+ */
597
+ public function setCharset($charset)
598
+ {
599
+ $this->charset = strtoupper($charset);
600
+ }
601
+
602
+ /**
603
+ * Gets the default template charset.
604
+ *
605
+ * @return string The default charset
606
+ */
607
+ public function getCharset()
608
+ {
609
+ return $this->charset;
610
+ }
611
+
612
+ /**
613
+ * Initializes the runtime environment.
614
+ */
615
+ public function initRuntime()
616
+ {
617
+ $this->runtimeInitialized = true;
618
+
619
+ foreach ($this->getExtensions() as $extension) {
620
+ $extension->initRuntime($this);
621
+ }
622
+ }
623
+
624
+ /**
625
+ * Returns true if the given extension is registered.
626
+ *
627
+ * @param string $name The extension name
628
+ *
629
+ * @return Boolean Whether the extension is registered or not
630
+ */
631
+ public function hasExtension($name)
632
+ {
633
+ return isset($this->extensions[$name]);
634
+ }
635
+
636
+ /**
637
+ * Gets an extension by name.
638
+ *
639
+ * @param string $name The extension name
640
+ *
641
+ * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
642
+ */
643
+ public function getExtension($name)
644
+ {
645
+ if (!isset($this->extensions[$name])) {
646
+ throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
647
+ }
648
+
649
+ return $this->extensions[$name];
650
+ }
651
+
652
+ /**
653
+ * Registers an extension.
654
+ *
655
+ * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
656
+ */
657
+ public function addExtension(Twig_ExtensionInterface $extension)
658
+ {
659
+ if ($this->extensionInitialized) {
660
+ throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
661
+ }
662
+
663
+ $this->extensions[$extension->getName()] = $extension;
664
+ }
665
+
666
+ /**
667
+ * Removes an extension by name.
668
+ *
669
+ * This method is deprecated and you should not use it.
670
+ *
671
+ * @param string $name The extension name
672
+ *
673
+ * @deprecated since 1.12 (to be removed in 2.0)
674
+ */
675
+ public function removeExtension($name)
676
+ {
677
+ if ($this->extensionInitialized) {
678
+ throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
679
+ }
680
+
681
+ unset($this->extensions[$name]);
682
+ }
683
+
684
+ /**
685
+ * Registers an array of extensions.
686
+ *
687
+ * @param array $extensions An array of extensions
688
+ */
689
+ public function setExtensions(array $extensions)
690
+ {
691
+ foreach ($extensions as $extension) {
692
+ $this->addExtension($extension);
693
+ }
694
+ }
695
+
696
+ /**
697
+ * Returns all registered extensions.
698
+ *
699
+ * @return array An array of extensions
700
+ */
701
+ public function getExtensions()
702
+ {
703
+ return $this->extensions;
704
+ }
705
+
706
+ /**
707
+ * Registers a Token Parser.
708
+ *
709
+ * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
710
+ */
711
+ public function addTokenParser(Twig_TokenParserInterface $parser)
712
+ {
713
+ if ($this->extensionInitialized) {
714
+ throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
715
+ }
716
+
717
+ $this->staging->addTokenParser($parser);
718
+ }
719
+
720
+ /**
721
+ * Gets the registered Token Parsers.
722
+ *
723
+ * @return Twig_TokenParserBrokerInterface A broker containing token parsers
724
+ */
725
+ public function getTokenParsers()
726
+ {
727
+ if (!$this->extensionInitialized) {
728
+ $this->initExtensions();
729
+ }
730
+
731
+ return $this->parsers;
732
+ }
733
+
734
+ /**
735
+ * Gets registered tags.
736
+ *
737
+ * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
738
+ *
739
+ * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
740
+ */
741
+ public function getTags()
742
+ {
743
+ $tags = array();
744
+ foreach ($this->getTokenParsers()->getParsers() as $parser) {
745
+ if ($parser instanceof Twig_TokenParserInterface) {
746
+ $tags[$parser->getTag()] = $parser;
747
+ }
748
+ }
749
+
750
+ return $tags;
751
+ }
752
+
753
+ /**
754
+ * Registers a Node Visitor.
755
+ *
756
+ * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
757
+ */
758
+ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
759
+ {
760
+ if ($this->extensionInitialized) {
761
+ throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
762
+ }
763
+
764
+ $this->staging->addNodeVisitor($visitor);
765
+ }
766
+
767
+ /**
768
+ * Gets the registered Node Visitors.
769
+ *
770
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
771
+ */
772
+ public function getNodeVisitors()
773
+ {
774
+ if (!$this->extensionInitialized) {
775
+ $this->initExtensions();
776
+ }
777
+
778
+ return $this->visitors;
779
+ }
780
+
781
+ /**
782
+ * Registers a Filter.
783
+ *
784
+ * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance
785
+ * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
786
+ */
787
+ public function addFilter($name, $filter = null)
788
+ {
789
+ if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
790
+ throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
791
+ }
792
+
793
+ if ($name instanceof Twig_SimpleFilter) {
794
+ $filter = $name;
795
+ $name = $filter->getName();
796
+ }
797
+
798
+ if ($this->extensionInitialized) {
799
+ throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
800
+ }
801
+
802
+ $this->staging->addFilter($name, $filter);
803
+ }
804
+
805
+ /**
806
+ * Get a filter by name.
807
+ *
808
+ * Subclasses may override this method and load filters differently;
809
+ * so no list of filters is available.
810
+ *
811
+ * @param string $name The filter name
812
+ *
813
+ * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
814
+ */
815
+ public function getFilter($name)
816
+ {
817
+ if (!$this->extensionInitialized) {
818
+ $this->initExtensions();
819
+ }
820
+
821
+ if (isset($this->filters[$name])) {
822
+ return $this->filters[$name];
823
+ }
824
+
825
+ foreach ($this->filters as $pattern => $filter) {
826
+ $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
827
+
828
+ if ($count) {
829
+ if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
830
+ array_shift($matches);
831
+ $filter->setArguments($matches);
832
+
833
+ return $filter;
834
+ }
835
+ }
836
+ }
837
+
838
+ foreach ($this->filterCallbacks as $callback) {
839
+ if (false !== $filter = call_user_func($callback, $name)) {
840
+ return $filter;
841
+ }
842
+ }
843
+
844
+ return false;
845
+ }
846
+
847
+ public function registerUndefinedFilterCallback($callable)
848
+ {
849
+ $this->filterCallbacks[] = $callable;
850
+ }
851
+
852
+ /**
853
+ * Gets the registered Filters.
854
+ *
855
+ * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
856
+ *
857
+ * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
858
+ *
859
+ * @see registerUndefinedFilterCallback
860
+ */
861
+ public function getFilters()
862
+ {
863
+ if (!$this->extensionInitialized) {
864
+ $this->initExtensions();
865
+ }
866
+
867
+ return $this->filters;
868
+ }
869
+
870
+ /**
871
+ * Registers a Test.
872
+ *
873
+ * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance
874
+ * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
875
+ */
876
+ public function addTest($name, $test = null)
877
+ {
878
+ if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
879
+ throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
880
+ }
881
+
882
+ if ($name instanceof Twig_SimpleTest) {
883
+ $test = $name;
884
+ $name = $test->getName();
885
+ }
886
+
887
+ if ($this->extensionInitialized) {
888
+ throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
889
+ }
890
+
891
+ $this->staging->addTest($name, $test);
892
+ }
893
+
894
+ /**
895
+ * Gets the registered Tests.
896
+ *
897
+ * @return Twig_TestInterface[] An array of Twig_TestInterface instances
898
+ */
899
+ public function getTests()
900
+ {
901
+ if (!$this->extensionInitialized) {
902
+ $this->initExtensions();
903
+ }
904
+
905
+ return $this->tests;
906
+ }
907
+
908
+ /**
909
+ * Gets a test by name.
910
+ *
911
+ * @param string $name The test name
912
+ *
913
+ * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
914
+ */
915
+ public function getTest($name)
916
+ {
917
+ if (!$this->extensionInitialized) {
918
+ $this->initExtensions();
919
+ }
920
+
921
+ if (isset($this->tests[$name])) {
922
+ return $this->tests[$name];
923
+ }
924
+
925
+ return false;
926
+ }
927
+
928
+ /**
929
+ * Registers a Function.
930
+ *
931
+ * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance
932
+ * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
933
+ */
934
+ public function addFunction($name, $function = null)
935
+ {
936
+ if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
937
+ throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
938
+ }
939
+
940
+ if ($name instanceof Twig_SimpleFunction) {
941
+ $function = $name;
942
+ $name = $function->getName();
943
+ }
944
+
945
+ if ($this->extensionInitialized) {
946
+ throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
947
+ }
948
+
949
+ $this->staging->addFunction($name, $function);
950
+ }
951
+
952
+ /**
953
+ * Get a function by name.
954
+ *
955
+ * Subclasses may override this method and load functions differently;
956
+ * so no list of functions is available.
957
+ *
958
+ * @param string $name function name
959
+ *
960
+ * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
961
+ */
962
+ public function getFunction($name)
963
+ {
964
+ if (!$this->extensionInitialized) {
965
+ $this->initExtensions();
966
+ }
967
+
968
+ if (isset($this->functions[$name])) {
969
+ return $this->functions[$name];
970
+ }
971
+
972
+ foreach ($this->functions as $pattern => $function) {
973
+ $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
974
+
975
+ if ($count) {
976
+ if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
977
+ array_shift($matches);
978
+ $function->setArguments($matches);
979
+
980
+ return $function;
981
+ }
982
+ }
983
+ }
984
+
985
+ foreach ($this->functionCallbacks as $callback) {
986
+ if (false !== $function = call_user_func($callback, $name)) {
987
+ return $function;
988
+ }
989
+ }
990
+
991
+ return false;
992
+ }
993
+
994
+ public function registerUndefinedFunctionCallback($callable)
995
+ {
996
+ $this->functionCallbacks[] = $callable;
997
+ }
998
+
999
+ /**
1000
+ * Gets registered functions.
1001
+ *
1002
+ * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
1003
+ *
1004
+ * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
1005
+ *
1006
+ * @see registerUndefinedFunctionCallback
1007
+ */
1008
+ public function getFunctions()
1009
+ {
1010
+ if (!$this->extensionInitialized) {
1011
+ $this->initExtensions();
1012
+ }
1013
+
1014
+ return $this->functions;
1015
+ }
1016
+
1017
+ /**
1018
+ * Registers a Global.
1019
+ *
1020
+ * New globals can be added before compiling or rendering a template;
1021
+ * but after, you can only update existing globals.
1022
+ *
1023
+ * @param string $name The global name
1024
+ * @param mixed $value The global value
1025
+ */
1026
+ public function addGlobal($name, $value)
1027
+ {
1028
+ if ($this->extensionInitialized || $this->runtimeInitialized) {
1029
+ if (null === $this->globals) {
1030
+ $this->globals = $this->initGlobals();
1031
+ }
1032
+
1033
+ /* This condition must be uncommented in Twig 2.0
1034
+ if (!array_key_exists($name, $this->globals)) {
1035
+ throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
1036
+ }
1037
+ */
1038
+ }
1039
+
1040
+ if ($this->extensionInitialized || $this->runtimeInitialized) {
1041
+ // update the value
1042
+ $this->globals[$name] = $value;
1043
+ } else {
1044
+ $this->staging->addGlobal($name, $value);
1045
+ }
1046
+ }
1047
+
1048
+ /**
1049
+ * Gets the registered Globals.
1050
+ *
1051
+ * @return array An array of globals
1052
+ */
1053
+ public function getGlobals()
1054
+ {
1055
+ if (!$this->runtimeInitialized && !$this->extensionInitialized) {
1056
+ return $this->initGlobals();
1057
+ }
1058
+
1059
+ if (null === $this->globals) {
1060
+ $this->globals = $this->initGlobals();
1061
+ }
1062
+
1063
+ return $this->globals;
1064
+ }
1065
+
1066
+ /**
1067
+ * Merges a context with the defined globals.
1068
+ *
1069
+ * @param array $context An array representing the context
1070
+ *
1071
+ * @return array The context merged with the globals
1072
+ */
1073
+ public function mergeGlobals(array $context)
1074
+ {
1075
+ // we don't use array_merge as the context being generally
1076
+ // bigger than globals, this code is faster.
1077
+ foreach ($this->getGlobals() as $key => $value) {
1078
+ if (!array_key_exists($key, $context)) {
1079
+ $context[$key] = $value;
1080
+ }
1081
+ }
1082
+
1083
+ return $context;
1084
+ }
1085
+
1086
+ /**
1087
+ * Gets the registered unary Operators.
1088
+ *
1089
+ * @return array An array of unary operators
1090
+ */
1091
+ public function getUnaryOperators()
1092
+ {
1093
+ if (!$this->extensionInitialized) {
1094
+ $this->initExtensions();
1095
+ }
1096
+
1097
+ return $this->unaryOperators;
1098
+ }
1099
+
1100
+ /**
1101
+ * Gets the registered binary Operators.
1102
+ *
1103
+ * @return array An array of binary operators
1104
+ */
1105
+ public function getBinaryOperators()
1106
+ {
1107
+ if (!$this->extensionInitialized) {
1108
+ $this->initExtensions();
1109
+ }
1110
+
1111
+ return $this->binaryOperators;
1112
+ }
1113
+
1114
+ public function computeAlternatives($name, $items)
1115
+ {
1116
+ $alternatives = array();
1117
+ foreach ($items as $item) {
1118
+ $lev = levenshtein($name, $item);
1119
+ if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
1120
+ $alternatives[$item] = $lev;
1121
+ }
1122
+ }
1123
+ asort($alternatives);
1124
+
1125
+ return array_keys($alternatives);
1126
+ }
1127
+
1128
+ protected function initGlobals()
1129
+ {
1130
+ $globals = array();
1131
+ foreach ($this->extensions as $extension) {
1132
+ $extGlob = $extension->getGlobals();
1133
+ if (!is_array($extGlob)) {
1134
+ throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
1135
+ }
1136
+
1137
+ $globals[] = $extGlob;
1138
+ }
1139
+
1140
+ $globals[] = $this->staging->getGlobals();
1141
+
1142
+ return call_user_func_array('array_merge', $globals);
1143
+ }
1144
+
1145
+ protected function initExtensions()
1146
+ {
1147
+ if ($this->extensionInitialized) {
1148
+ return;
1149
+ }
1150
+
1151
+ $this->extensionInitialized = true;
1152
+ $this->parsers = new Twig_TokenParserBroker();
1153
+ $this->filters = array();
1154
+ $this->functions = array();
1155
+ $this->tests = array();
1156
+ $this->visitors = array();
1157
+ $this->unaryOperators = array();
1158
+ $this->binaryOperators = array();
1159
+
1160
+ foreach ($this->extensions as $extension) {
1161
+ $this->initExtension($extension);
1162
+ }
1163
+ $this->initExtension($this->staging);
1164
+ }
1165
+
1166
+ protected function initExtension(Twig_ExtensionInterface $extension)
1167
+ {
1168
+ // filters
1169
+ foreach ($extension->getFilters() as $name => $filter) {
1170
+ if ($name instanceof Twig_SimpleFilter) {
1171
+ $filter = $name;
1172
+ $name = $filter->getName();
1173
+ } elseif ($filter instanceof Twig_SimpleFilter) {
1174
+ $name = $filter->getName();
1175
+ }
1176
+
1177
+ $this->filters[$name] = $filter;
1178
+ }
1179
+
1180
+ // functions
1181
+ foreach ($extension->getFunctions() as $name => $function) {
1182
+ if ($name instanceof Twig_SimpleFunction) {
1183
+ $function = $name;
1184
+ $name = $function->getName();
1185
+ } elseif ($function instanceof Twig_SimpleFunction) {
1186
+ $name = $function->getName();
1187
+ }
1188
+
1189
+ $this->functions[$name] = $function;
1190
+ }
1191
+
1192
+ // tests
1193
+ foreach ($extension->getTests() as $name => $test) {
1194
+ if ($name instanceof Twig_SimpleTest) {
1195
+ $test = $name;
1196
+ $name = $test->getName();
1197
+ } elseif ($test instanceof Twig_SimpleTest) {
1198
+ $name = $test->getName();
1199
+ }
1200
+
1201
+ $this->tests[$name] = $test;
1202
+ }
1203
+
1204
+ // token parsers
1205
+ foreach ($extension->getTokenParsers() as $parser) {
1206
+ if ($parser instanceof Twig_TokenParserInterface) {
1207
+ $this->parsers->addTokenParser($parser);
1208
+ } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
1209
+ $this->parsers->addTokenParserBroker($parser);
1210
+ } else {
1211
+ throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
1212
+ }
1213
+ }
1214
+
1215
+ // node visitors
1216
+ foreach ($extension->getNodeVisitors() as $visitor) {
1217
+ $this->visitors[] = $visitor;
1218
+ }
1219
+
1220
+ // operators
1221
+ if ($operators = $extension->getOperators()) {
1222
+ if (2 !== count($operators)) {
1223
+ throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
1224
+ }
1225
+
1226
+ $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
1227
+ $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
1228
+ }
1229
+ }
1230
+
1231
+ protected function writeCacheFile($file, $content)
1232
+ {
1233
+ $dir = dirname($file);
1234
+ if (!is_dir($dir)) {
1235
+ if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
1236
+ throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
1237
+ }
1238
+ } elseif (!is_writable($dir)) {
1239
+ throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
1240
+ }
1241
+
1242
+ $tmpFile = tempnam($dir, basename($file));
1243
+ if (false !== @file_put_contents($tmpFile, $content)) {
1244
+ // rename does not work on Win32 before 5.2.6
1245
+ if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
1246
+ @chmod($file, 0666 & ~umask());
1247
+
1248
+ return;
1249
+ }
1250
+ }
1251
+
1252
+ throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
1253
+ }
1254
+ }
vendor/vendor/twig/twig/lib/Twig/Error.php ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig base exception.
14
+ *
15
+ * This exception class and its children must only be used when
16
+ * an error occurs during the loading of a template, when a syntax error
17
+ * is detected in a template, or when rendering a template. Other
18
+ * errors must use regular PHP exception classes (like when the template
19
+ * cache directory is not writable for instance).
20
+ *
21
+ * To help debugging template issues, this class tracks the original template
22
+ * name and line where the error occurred.
23
+ *
24
+ * Whenever possible, you must set these information (original template name
25
+ * and line number) yourself by passing them to the constructor. If some or all
26
+ * these information are not available from where you throw the exception, then
27
+ * this class will guess them automatically (when the line number is set to -1
28
+ * and/or the filename is set to null). As this is a costly operation, this
29
+ * can be disabled by passing false for both the filename and the line number
30
+ * when creating a new instance of this class.
31
+ *
32
+ * @author Fabien Potencier <fabien@symfony.com>
33
+ */
34
+ class Twig_Error extends Exception
35
+ {
36
+ protected $lineno;
37
+ protected $filename;
38
+ protected $rawMessage;
39
+ protected $previous;
40
+
41
+ /**
42
+ * Constructor.
43
+ *
44
+ * Set both the line number and the filename to false to
45
+ * disable automatic guessing of the original template name
46
+ * and line number.
47
+ *
48
+ * Set the line number to -1 to enable its automatic guessing.
49
+ * Set the filename to null to enable its automatic guessing.
50
+ *
51
+ * By default, automatic guessing is enabled.
52
+ *
53
+ * @param string $message The error message
54
+ * @param integer $lineno The template line where the error occurred
55
+ * @param string $filename The template file name where the error occurred
56
+ * @param Exception $previous The previous exception
57
+ */
58
+ public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
59
+ {
60
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
61
+ $this->previous = $previous;
62
+ parent::__construct('');
63
+ } else {
64
+ parent::__construct('', 0, $previous);
65
+ }
66
+
67
+ $this->lineno = $lineno;
68
+ $this->filename = $filename;
69
+
70
+ if (-1 === $this->lineno || null === $this->filename) {
71
+ $this->guessTemplateInfo();
72
+ }
73
+
74
+ $this->rawMessage = $message;
75
+
76
+ $this->updateRepr();
77
+ }
78
+
79
+ /**
80
+ * Gets the raw message.
81
+ *
82
+ * @return string The raw message
83
+ */
84
+ public function getRawMessage()
85
+ {
86
+ return $this->rawMessage;
87
+ }
88
+
89
+ /**
90
+ * Gets the filename where the error occurred.
91
+ *
92
+ * @return string The filename
93
+ */
94
+ public function getTemplateFile()
95
+ {
96
+ return $this->filename;
97
+ }
98
+
99
+ /**
100
+ * Sets the filename where the error occurred.
101
+ *
102
+ * @param string $filename The filename
103
+ */
104
+ public function setTemplateFile($filename)
105
+ {
106
+ $this->filename = $filename;
107
+
108
+ $this->updateRepr();
109
+ }
110
+
111
+ /**
112
+ * Gets the template line where the error occurred.
113
+ *
114
+ * @return integer The template line
115
+ */
116
+ public function getTemplateLine()
117
+ {
118
+ return $this->lineno;
119
+ }
120
+
121
+ /**
122
+ * Sets the template line where the error occurred.
123
+ *
124
+ * @param integer $lineno The template line
125
+ */
126
+ public function setTemplateLine($lineno)
127
+ {
128
+ $this->lineno = $lineno;
129
+
130
+ $this->updateRepr();
131
+ }
132
+
133
+ public function guess()
134
+ {
135
+ $this->guessTemplateInfo();
136
+ $this->updateRepr();
137
+ }
138
+
139
+ /**
140
+ * For PHP < 5.3.0, provides access to the getPrevious() method.
141
+ *
142
+ * @param string $method The method name
143
+ * @param array $arguments The parameters to be passed to the method
144
+ *
145
+ * @return Exception The previous exception or null
146
+ *
147
+ * @throws BadMethodCallException
148
+ */
149
+ public function __call($method, $arguments)
150
+ {
151
+ if ('getprevious' == strtolower($method)) {
152
+ return $this->previous;
153
+ }
154
+
155
+ throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
156
+ }
157
+
158
+ protected function updateRepr()
159
+ {
160
+ $this->message = $this->rawMessage;
161
+
162
+ $dot = false;
163
+ if ('.' === substr($this->message, -1)) {
164
+ $this->message = substr($this->message, 0, -1);
165
+ $dot = true;
166
+ }
167
+
168
+ if ($this->filename) {
169
+ if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
170
+ $filename = sprintf('"%s"', $this->filename);
171
+ } else {
172
+ $filename = json_encode($this->filename);
173
+ }
174
+ $this->message .= sprintf(' in %s', $filename);
175
+ }
176
+
177
+ if ($this->lineno && $this->lineno >= 0) {
178
+ $this->message .= sprintf(' at line %d', $this->lineno);
179
+ }
180
+
181
+ if ($dot) {
182
+ $this->message .= '.';
183
+ }
184
+ }
185
+
186
+ protected function guessTemplateInfo()
187
+ {
188
+ $template = null;
189
+ $templateClass = null;
190
+
191
+ if (version_compare(phpversion(), '5.3.6', '>=')) {
192
+ $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
193
+ } else {
194
+ $backtrace = debug_backtrace();
195
+ }
196
+
197
+ foreach ($backtrace as $trace) {
198
+ if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
199
+ $currentClass = get_class($trace['object']);
200
+ $isEmbedContainer = 0 === strpos($templateClass, $currentClass);
201
+ if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
202
+ $template = $trace['object'];
203
+ $templateClass = get_class($trace['object']);
204
+ }
205
+ }
206
+ }
207
+
208
+ // update template filename
209
+ if (null !== $template && null === $this->filename) {
210
+ $this->filename = $template->getTemplateName();
211
+ }
212
+
213
+ if (null === $template || $this->lineno > -1) {
214
+ return;
215
+ }
216
+
217
+ $r = new ReflectionObject($template);
218
+ $file = $r->getFileName();
219
+
220
+ // hhvm has a bug where eval'ed files comes out as the current directory
221
+ if (is_dir($file)) {
222
+ $file = '';
223
+ }
224
+
225
+ $exceptions = array($e = $this);
226
+ while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
227
+ $exceptions[] = $e;
228
+ }
229
+
230
+ while ($e = array_pop($exceptions)) {
231
+ $traces = $e->getTrace();
232
+ while ($trace = array_shift($traces)) {
233
+ if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
234
+ continue;
235
+ }
236
+
237
+ foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
238
+ if ($codeLine <= $trace['line']) {
239
+ // update template line
240
+ $this->lineno = $templateLine;
241
+
242
+ return;
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ }
vendor/vendor/twig/twig/lib/Twig/Error/Loader.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Exception thrown when an error occurs during template loading.
14
+ *
15
+ * Automatic template information guessing is always turned off as
16
+ * if a template cannot be loaded, there is nothing to guess.
17
+ * However, when a template is loaded from another one, then, we need
18
+ * to find the current context and this is automatically done by
19
+ * Twig_Template::displayWithErrorHandling().
20
+ *
21
+ * This strategy makes Twig_Environment::resolveTemplate() much faster.
22
+ *
23
+ * @author Fabien Potencier <fabien@symfony.com>
24
+ */
25
+ class Twig_Error_Loader extends Twig_Error
26
+ {
27
+ public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
28
+ {
29
+ parent::__construct($message, false, false, $previous);
30
+ }
31
+ }
vendor/vendor/twig/twig/lib/Twig/Error/Runtime.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Exception thrown when an error occurs at runtime.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Error_Runtime extends Twig_Error
19
+ {
20
+ }
vendor/vendor/twig/twig/lib/Twig/Error/Syntax.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Exception thrown when a syntax error occurs during lexing or parsing of a template.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Error_Syntax extends Twig_Error
19
+ {
20
+ }
vendor/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Adds an exists() method for loaders.
14
+ *
15
+ * @author Florin Patan <florinpatan@gmail.com>
16
+ * @deprecated since 1.12 (to be removed in 2.0)
17
+ */
18
+ interface Twig_ExistsLoaderInterface
19
+ {
20
+ /**
21
+ * Check if we have the source code of a template, given its name.
22
+ *
23
+ * @param string $name The name of the template to check if we can load
24
+ *
25
+ * @return Boolean If the template source code is handled by this loader or not
26
+ */
27
+ public function exists($name);
28
+ }
vendor/vendor/twig/twig/lib/Twig/ExpressionParser.php ADDED
@@ -0,0 +1,598 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Parses expressions.
15
+ *
16
+ * This parser implements a "Precedence climbing" algorithm.
17
+ *
18
+ * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
19
+ * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
20
+ *
21
+ * @author Fabien Potencier <fabien@symfony.com>
22
+ */
23
+ class Twig_ExpressionParser
24
+ {
25
+ const OPERATOR_LEFT = 1;
26
+ const OPERATOR_RIGHT = 2;
27
+
28
+ protected $parser;
29
+ protected $unaryOperators;
30
+ protected $binaryOperators;
31
+
32
+ public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
33
+ {
34
+ $this->parser = $parser;
35
+ $this->unaryOperators = $unaryOperators;
36
+ $this->binaryOperators = $binaryOperators;
37
+ }
38
+
39
+ public function parseExpression($precedence = 0)
40
+ {
41
+ $expr = $this->getPrimary();
42
+ $token = $this->parser->getCurrentToken();
43
+ while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
44
+ $op = $this->binaryOperators[$token->getValue()];
45
+ $this->parser->getStream()->next();
46
+
47
+ if (isset($op['callable'])) {
48
+ $expr = call_user_func($op['callable'], $this->parser, $expr);
49
+ } else {
50
+ $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
51
+ $class = $op['class'];
52
+ $expr = new $class($expr, $expr1, $token->getLine());
53
+ }
54
+
55
+ $token = $this->parser->getCurrentToken();
56
+ }
57
+
58
+ if (0 === $precedence) {
59
+ return $this->parseConditionalExpression($expr);
60
+ }
61
+
62
+ return $expr;
63
+ }
64
+
65
+ protected function getPrimary()
66
+ {
67
+ $token = $this->parser->getCurrentToken();
68
+
69
+ if ($this->isUnary($token)) {
70
+ $operator = $this->unaryOperators[$token->getValue()];
71
+ $this->parser->getStream()->next();
72
+ $expr = $this->parseExpression($operator['precedence']);
73
+ $class = $operator['class'];
74
+
75
+ return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
76
+ } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
77
+ $this->parser->getStream()->next();
78
+ $expr = $this->parseExpression();
79
+ $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
80
+
81
+ return $this->parsePostfixExpression($expr);
82
+ }
83
+
84
+ return $this->parsePrimaryExpression();
85
+ }
86
+
87
+ protected function parseConditionalExpression($expr)
88
+ {
89
+ while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
90
+ if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
91
+ $expr2 = $this->parseExpression();
92
+ if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
93
+ $expr3 = $this->parseExpression();
94
+ } else {
95
+ $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
96
+ }
97
+ } else {
98
+ $expr2 = $expr;
99
+ $expr3 = $this->parseExpression();
100
+ }
101
+
102
+ $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
103
+ }
104
+
105
+ return $expr;
106
+ }
107
+
108
+ protected function isUnary(Twig_Token $token)
109
+ {
110
+ return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
111
+ }
112
+
113
+ protected function isBinary(Twig_Token $token)
114
+ {
115
+ return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
116
+ }
117
+
118
+ public function parsePrimaryExpression()
119
+ {
120
+ $token = $this->parser->getCurrentToken();
121
+ switch ($token->getType()) {
122
+ case Twig_Token::NAME_TYPE:
123
+ $this->parser->getStream()->next();
124
+ switch ($token->getValue()) {
125
+ case 'true':
126
+ case 'TRUE':
127
+ $node = new Twig_Node_Expression_Constant(true, $token->getLine());
128
+ break;
129
+
130
+ case 'false':
131
+ case 'FALSE':
132
+ $node = new Twig_Node_Expression_Constant(false, $token->getLine());
133
+ break;
134
+
135
+ case 'none':
136
+ case 'NONE':
137
+ case 'null':
138
+ case 'NULL':
139
+ $node = new Twig_Node_Expression_Constant(null, $token->getLine());
140
+ break;
141
+
142
+ default:
143
+ if ('(' === $this->parser->getCurrentToken()->getValue()) {
144
+ $node = $this->getFunctionNode($token->getValue(), $token->getLine());
145
+ } else {
146
+ $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
147
+ }
148
+ }
149
+ break;
150
+
151
+ case Twig_Token::NUMBER_TYPE:
152
+ $this->parser->getStream()->next();
153
+ $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
154
+ break;
155
+
156
+ case Twig_Token::STRING_TYPE:
157
+ case Twig_Token::INTERPOLATION_START_TYPE:
158
+ $node = $this->parseStringExpression();
159
+ break;
160
+
161
+ case Twig_Token::OPERATOR_TYPE:
162
+ if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
163
+ // in this context, string operators are variable names
164
+ $this->parser->getStream()->next();
165
+ $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
166
+ break;
167
+ }
168
+
169
+ default:
170
+ if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
171
+ $node = $this->parseArrayExpression();
172
+ } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
173
+ $node = $this->parseHashExpression();
174
+ } else {
175
+ throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
176
+ }
177
+ }
178
+
179
+ return $this->parsePostfixExpression($node);
180
+ }
181
+
182
+ public function parseStringExpression()
183
+ {
184
+ $stream = $this->parser->getStream();
185
+
186
+ $nodes = array();
187
+ // a string cannot be followed by another string in a single expression
188
+ $nextCanBeString = true;
189
+ while (true) {
190
+ if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
191
+ $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
192
+ $nextCanBeString = false;
193
+ } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
194
+ $nodes[] = $this->parseExpression();
195
+ $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
196
+ $nextCanBeString = true;
197
+ } else {
198
+ break;
199
+ }
200
+ }
201
+
202
+ $expr = array_shift($nodes);
203
+ foreach ($nodes as $node) {
204
+ $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
205
+ }
206
+
207
+ return $expr;
208
+ }
209
+
210
+ public function parseArrayExpression()
211
+ {
212
+ $stream = $this->parser->getStream();
213
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
214
+
215
+ $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
216
+ $first = true;
217
+ while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
218
+ if (!$first) {
219
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
220
+
221
+ // trailing ,?
222
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
223
+ break;
224
+ }
225
+ }
226
+ $first = false;
227
+
228
+ $node->addElement($this->parseExpression());
229
+ }
230
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
231
+
232
+ return $node;
233
+ }
234
+
235
+ public function parseHashExpression()
236
+ {
237
+ $stream = $this->parser->getStream();
238
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
239
+
240
+ $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
241
+ $first = true;
242
+ while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
243
+ if (!$first) {
244
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
245
+
246
+ // trailing ,?
247
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
248
+ break;
249
+ }
250
+ }
251
+ $first = false;
252
+
253
+ // a hash key can be:
254
+ //
255
+ // * a number -- 12
256
+ // * a string -- 'a'
257
+ // * a name, which is equivalent to a string -- a
258
+ // * an expression, which must be enclosed in parentheses -- (1 + 2)
259
+ if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
260
+ $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
261
+ } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
262
+ $key = $this->parseExpression();
263
+ } else {
264
+ $current = $stream->getCurrent();
265
+
266
+ throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
267
+ }
268
+
269
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
270
+ $value = $this->parseExpression();
271
+
272
+ $node->addElement($value, $key);
273
+ }
274
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
275
+
276
+ return $node;
277
+ }
278
+
279
+ public function parsePostfixExpression($node)
280
+ {
281
+ while (true) {
282
+ $token = $this->parser->getCurrentToken();
283
+ if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
284
+ if ('.' == $token->getValue() || '[' == $token->getValue()) {
285
+ $node = $this->parseSubscriptExpression($node);
286
+ } elseif ('|' == $token->getValue()) {
287
+ $node = $this->parseFilterExpression($node);
288
+ } else {
289
+ break;
290
+ }
291
+ } else {
292
+ break;
293
+ }
294
+ }
295
+
296
+ return $node;
297
+ }
298
+
299
+ public function getFunctionNode($name, $line)
300
+ {
301
+ switch ($name) {
302
+ case 'parent':
303
+ $args = $this->parseArguments();
304
+ if (!count($this->parser->getBlockStack())) {
305
+ throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
306
+ }
307
+
308
+ if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
309
+ throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
310
+ }
311
+
312
+ return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
313
+ case 'block':
314
+ return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
315
+ case 'attribute':
316
+ $args = $this->parseArguments();
317
+ if (count($args) < 2) {
318
+ throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
319
+ }
320
+
321
+ return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line);
322
+ default:
323
+ if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
324
+ $arguments = new Twig_Node_Expression_Array(array(), $line);
325
+ foreach ($this->parseArguments() as $n) {
326
+ $arguments->addElement($n);
327
+ }
328
+
329
+ $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
330
+ $node->setAttribute('safe', true);
331
+
332
+ return $node;
333
+ }
334
+
335
+ $args = $this->parseArguments(true);
336
+ $class = $this->getFunctionNodeClass($name, $line);
337
+
338
+ return new $class($name, $args, $line);
339
+ }
340
+ }
341
+
342
+ public function parseSubscriptExpression($node)
343
+ {
344
+ $stream = $this->parser->getStream();
345
+ $token = $stream->next();
346
+ $lineno = $token->getLine();
347
+ $arguments = new Twig_Node_Expression_Array(array(), $lineno);
348
+ $type = Twig_Template::ANY_CALL;
349
+ if ($token->getValue() == '.') {
350
+ $token = $stream->next();
351
+ if (
352
+ $token->getType() == Twig_Token::NAME_TYPE
353
+ ||
354
+ $token->getType() == Twig_Token::NUMBER_TYPE
355
+ ||
356
+ ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
357
+ ) {
358
+ $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
359
+
360
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
361
+ $type = Twig_TemplateInterface::METHOD_CALL;
362
+ foreach ($this->parseArguments() as $n) {
363
+ $arguments->addElement($n);
364
+ }
365
+ }
366
+ } else {
367
+ throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
368
+ }
369
+
370
+ if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
371
+ if (!$arg instanceof Twig_Node_Expression_Constant) {
372
+ throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
373
+ }
374
+
375
+ $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
376
+ $node->setAttribute('safe', true);
377
+
378
+ return $node;
379
+ }
380
+ } else {
381
+ $type = Twig_Template::ARRAY_CALL;
382
+
383
+ // slice?
384
+ $slice = false;
385
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
386
+ $slice = true;
387
+ $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
388
+ } else {
389
+ $arg = $this->parseExpression();
390
+ }
391
+
392
+ if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
393
+ $slice = true;
394
+ }
395
+
396
+ if ($slice) {
397
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
398
+ $length = new Twig_Node_Expression_Constant(null, $token->getLine());
399
+ } else {
400
+ $length = $this->parseExpression();
401
+ }
402
+
403
+ $class = $this->getFilterNodeClass('slice', $token->getLine());
404
+ $arguments = new Twig_Node(array($arg, $length));
405
+ $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
406
+
407
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
408
+
409
+ return $filter;
410
+ }
411
+
412
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
413
+ }
414
+
415
+ return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
416
+ }
417
+
418
+ public function parseFilterExpression($node)
419
+ {
420
+ $this->parser->getStream()->next();
421
+
422
+ return $this->parseFilterExpressionRaw($node);
423
+ }
424
+
425
+ public function parseFilterExpressionRaw($node, $tag = null)
426
+ {
427
+ while (true) {
428
+ $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
429
+
430
+ $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
431
+ if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
432
+ $arguments = new Twig_Node();
433
+ } else {
434
+ $arguments = $this->parseArguments(true);
435
+ }
436
+
437
+ $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
438
+
439
+ $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
440
+
441
+ if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
442
+ break;
443
+ }
444
+
445
+ $this->parser->getStream()->next();
446
+ }
447
+
448
+ return $node;
449
+ }
450
+
451
+ /**
452
+ * Parses arguments.
453
+ *
454
+ * @param Boolean $namedArguments Whether to allow named arguments or not
455
+ * @param Boolean $definition Whether we are parsing arguments for a function definition
456
+ */
457
+ public function parseArguments($namedArguments = false, $definition = false)
458
+ {
459
+ $args = array();
460
+ $stream = $this->parser->getStream();
461
+
462
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
463
+ while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
464
+ if (!empty($args)) {
465
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
466
+ }
467
+
468
+ if ($definition) {
469
+ $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
470
+ $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
471
+ } else {
472
+ $value = $this->parseExpression();
473
+ }
474
+
475
+ $name = null;
476
+ if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
477
+ if (!$value instanceof Twig_Node_Expression_Name) {
478
+ throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
479
+ }
480
+ $name = $value->getAttribute('name');
481
+
482
+ if ($definition) {
483
+ $value = $this->parsePrimaryExpression();
484
+
485
+ if (!$this->checkConstantExpression($value)) {
486
+ throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
487
+ }
488
+ } else {
489
+ $value = $this->parseExpression();
490
+ }
491
+ }
492
+
493
+ if ($definition) {
494
+ if (null === $name) {
495
+ $name = $value->getAttribute('name');
496
+ $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
497
+ }
498
+ $args[$name] = $value;
499
+ } else {
500
+ if (null === $name) {
501
+ $args[] = $value;
502
+ } else {
503
+ $args[$name] = $value;
504
+ }
505
+ }
506
+ }
507
+ $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
508
+
509
+ return new Twig_Node($args);
510
+ }
511
+
512
+ public function parseAssignmentExpression()
513
+ {
514
+ $targets = array();
515
+ while (true) {
516
+ $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
517
+ if (in_array($token->getValue(), array('true', 'false', 'none'))) {
518
+ throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
519
+ }
520
+ $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
521
+
522
+ if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
523
+ break;
524
+ }
525
+ }
526
+
527
+ return new Twig_Node($targets);
528
+ }
529
+
530
+ public function parseMultitargetExpression()
531
+ {
532
+ $targets = array();
533
+ while (true) {
534
+ $targets[] = $this->parseExpression();
535
+ if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
536
+ break;
537
+ }
538
+ }
539
+
540
+ return new Twig_Node($targets);
541
+ }
542
+
543
+ protected function getFunctionNodeClass($name, $line)
544
+ {
545
+ $env = $this->parser->getEnvironment();
546
+
547
+ if (false === $function = $env->getFunction($name)) {
548
+ $message = sprintf('The function "%s" does not exist', $name);
549
+ if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
550
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
551
+ }
552
+
553
+ throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
554
+ }
555
+
556
+ if ($function instanceof Twig_SimpleFunction) {
557
+ return $function->getNodeClass();
558
+ }
559
+
560
+ return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
561
+ }
562
+
563
+ protected function getFilterNodeClass($name, $line)
564
+ {
565
+ $env = $this->parser->getEnvironment();
566
+
567
+ if (false === $filter = $env->getFilter($name)) {
568
+ $message = sprintf('The filter "%s" does not exist', $name);
569
+ if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
570
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
571
+ }
572
+
573
+ throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
574
+ }
575
+
576
+ if ($filter instanceof Twig_SimpleFilter) {
577
+ return $filter->getNodeClass();
578
+ }
579
+
580
+ return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
581
+ }
582
+
583
+ // checks that the node only contains "constant" elements
584
+ protected function checkConstantExpression(Twig_NodeInterface $node)
585
+ {
586
+ if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
587
+ return false;
588
+ }
589
+
590
+ foreach ($node as $n) {
591
+ if (!$this->checkConstantExpression($n)) {
592
+ return false;
593
+ }
594
+ }
595
+
596
+ return true;
597
+ }
598
+ }
vendor/vendor/twig/twig/lib/Twig/Extension.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ abstract class Twig_Extension implements Twig_ExtensionInterface
12
+ {
13
+ /**
14
+ * Initializes the runtime environment.
15
+ *
16
+ * This is where you can load some file that contains filter functions for instance.
17
+ *
18
+ * @param Twig_Environment $environment The current Twig_Environment instance
19
+ */
20
+ public function initRuntime(Twig_Environment $environment)
21
+ {
22
+ }
23
+
24
+ /**
25
+ * Returns the token parser instances to add to the existing list.
26
+ *
27
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
28
+ */
29
+ public function getTokenParsers()
30
+ {
31
+ return array();
32
+ }
33
+
34
+ /**
35
+ * Returns the node visitor instances to add to the existing list.
36
+ *
37
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
38
+ */
39
+ public function getNodeVisitors()
40
+ {
41
+ return array();
42
+ }
43
+
44
+ /**
45
+ * Returns a list of filters to add to the existing list.
46
+ *
47
+ * @return array An array of filters
48
+ */
49
+ public function getFilters()
50
+ {
51
+ return array();
52
+ }
53
+
54
+ /**
55
+ * Returns a list of tests to add to the existing list.
56
+ *
57
+ * @return array An array of tests
58
+ */
59
+ public function getTests()
60
+ {
61
+ return array();
62
+ }
63
+
64
+ /**
65
+ * Returns a list of functions to add to the existing list.
66
+ *
67
+ * @return array An array of functions
68
+ */
69
+ public function getFunctions()
70
+ {
71
+ return array();
72
+ }
73
+
74
+ /**
75
+ * Returns a list of operators to add to the existing list.
76
+ *
77
+ * @return array An array of operators
78
+ */
79
+ public function getOperators()
80
+ {
81
+ return array();
82
+ }
83
+
84
+ /**
85
+ * Returns a list of global variables to add to the existing list.
86
+ *
87
+ * @return array An array of global variables
88
+ */
89
+ public function getGlobals()
90
+ {
91
+ return array();
92
+ }
93
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/Core.php ADDED
@@ -0,0 +1,1463 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('ENT_SUBSTITUTE')) {
4
+ // use 0 as hhvm does not support several flags yet
5
+ define('ENT_SUBSTITUTE', 0);
6
+ }
7
+
8
+ /*
9
+ * This file is part of Twig.
10
+ *
11
+ * (c) 2009 Fabien Potencier
12
+ *
13
+ * For the full copyright and license information, please view the LICENSE
14
+ * file that was distributed with this source code.
15
+ */
16
+ class Twig_Extension_Core extends Twig_Extension
17
+ {
18
+ protected $dateFormats = array('F j, Y H:i', '%d days');
19
+ protected $numberFormat = array(0, '.', ',');
20
+ protected $timezone = null;
21
+ protected $escapers = array();
22
+
23
+ /**
24
+ * Defines a new escaper to be used via the escape filter.
25
+ *
26
+ * @param string $strategy The strategy name that should be used as a strategy in the escape call
27
+ * @param callable $callable A valid PHP callable
28
+ */
29
+ public function setEscaper($strategy, $callable)
30
+ {
31
+ $this->escapers[$strategy] = $callable;
32
+ }
33
+
34
+ /**
35
+ * Gets all defined escapers.
36
+ *
37
+ * @return array An array of escapers
38
+ */
39
+ public function getEscapers()
40
+ {
41
+ return $this->escapers;
42
+ }
43
+
44
+ /**
45
+ * Sets the default format to be used by the date filter.
46
+ *
47
+ * @param string $format The default date format string
48
+ * @param string $dateIntervalFormat The default date interval format string
49
+ */
50
+ public function setDateFormat($format = null, $dateIntervalFormat = null)
51
+ {
52
+ if (null !== $format) {
53
+ $this->dateFormats[0] = $format;
54
+ }
55
+
56
+ if (null !== $dateIntervalFormat) {
57
+ $this->dateFormats[1] = $dateIntervalFormat;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Gets the default format to be used by the date filter.
63
+ *
64
+ * @return array The default date format string and the default date interval format string
65
+ */
66
+ public function getDateFormat()
67
+ {
68
+ return $this->dateFormats;
69
+ }
70
+
71
+ /**
72
+ * Sets the default timezone to be used by the date filter.
73
+ *
74
+ * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object
75
+ */
76
+ public function setTimezone($timezone)
77
+ {
78
+ $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone);
79
+ }
80
+
81
+ /**
82
+ * Gets the default timezone to be used by the date filter.
83
+ *
84
+ * @return DateTimeZone The default timezone currently in use
85
+ */
86
+ public function getTimezone()
87
+ {
88
+ if (null === $this->timezone) {
89
+ $this->timezone = new DateTimeZone(date_default_timezone_get());
90
+ }
91
+
92
+ return $this->timezone;
93
+ }
94
+
95
+ /**
96
+ * Sets the default format to be used by the number_format filter.
97
+ *
98
+ * @param integer $decimal The number of decimal places to use.
99
+ * @param string $decimalPoint The character(s) to use for the decimal point.
100
+ * @param string $thousandSep The character(s) to use for the thousands separator.
101
+ */
102
+ public function setNumberFormat($decimal, $decimalPoint, $thousandSep)
103
+ {
104
+ $this->numberFormat = array($decimal, $decimalPoint, $thousandSep);
105
+ }
106
+
107
+ /**
108
+ * Get the default format used by the number_format filter.
109
+ *
110
+ * @return array The arguments for number_format()
111
+ */
112
+ public function getNumberFormat()
113
+ {
114
+ return $this->numberFormat;
115
+ }
116
+
117
+ /**
118
+ * Returns the token parser instance to add to the existing list.
119
+ *
120
+ * @return Twig_TokenParser[] An array of Twig_TokenParser instances
121
+ */
122
+ public function getTokenParsers()
123
+ {
124
+ return array(
125
+ new Twig_TokenParser_For(),
126
+ new Twig_TokenParser_If(),
127
+ new Twig_TokenParser_Extends(),
128
+ new Twig_TokenParser_Include(),
129
+ new Twig_TokenParser_Block(),
130
+ new Twig_TokenParser_Use(),
131
+ new Twig_TokenParser_Filter(),
132
+ new Twig_TokenParser_Macro(),
133
+ new Twig_TokenParser_Import(),
134
+ new Twig_TokenParser_From(),
135
+ new Twig_TokenParser_Set(),
136
+ new Twig_TokenParser_Spaceless(),
137
+ new Twig_TokenParser_Flush(),
138
+ new Twig_TokenParser_Do(),
139
+ new Twig_TokenParser_Embed(),
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Returns a list of filters to add to the existing list.
145
+ *
146
+ * @return array An array of filters
147
+ */
148
+ public function getFilters()
149
+ {
150
+ $filters = array(
151
+ // formatting filters
152
+ new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
153
+ new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
154
+ new Twig_SimpleFilter('format', 'sprintf'),
155
+ new Twig_SimpleFilter('replace', 'strtr'),
156
+ new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
157
+ new Twig_SimpleFilter('abs', 'abs'),
158
+ new Twig_SimpleFilter('round', 'twig_round'),
159
+
160
+ // encoding
161
+ new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'),
162
+ new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'),
163
+ new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'),
164
+
165
+ // string filters
166
+ new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)),
167
+ new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)),
168
+ new Twig_SimpleFilter('upper', 'strtoupper'),
169
+ new Twig_SimpleFilter('lower', 'strtolower'),
170
+ new Twig_SimpleFilter('striptags', 'strip_tags'),
171
+ new Twig_SimpleFilter('trim', 'trim'),
172
+ new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))),
173
+
174
+ // array helpers
175
+ new Twig_SimpleFilter('join', 'twig_join_filter'),
176
+ new Twig_SimpleFilter('split', 'twig_split_filter'),
177
+ new Twig_SimpleFilter('sort', 'twig_sort_filter'),
178
+ new Twig_SimpleFilter('merge', 'twig_array_merge'),
179
+ new Twig_SimpleFilter('batch', 'twig_array_batch'),
180
+
181
+ // string/array filters
182
+ new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)),
183
+ new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)),
184
+ new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)),
185
+ new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)),
186
+ new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)),
187
+
188
+ // iteration and runtime
189
+ new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')),
190
+ new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'),
191
+
192
+ // escaping
193
+ new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
194
+ new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')),
195
+ );
196
+
197
+ if (function_exists('mb_get_info')) {
198
+ $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true));
199
+ $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true));
200
+ }
201
+
202
+ return $filters;
203
+ }
204
+
205
+ /**
206
+ * Returns a list of global functions to add to the existing list.
207
+ *
208
+ * @return array An array of global functions
209
+ */
210
+ public function getFunctions()
211
+ {
212
+ return array(
213
+ new Twig_SimpleFunction('max', 'max'),
214
+ new Twig_SimpleFunction('min', 'min'),
215
+ new Twig_SimpleFunction('range', 'range'),
216
+ new Twig_SimpleFunction('constant', 'twig_constant'),
217
+ new Twig_SimpleFunction('cycle', 'twig_cycle'),
218
+ new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)),
219
+ new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)),
220
+ new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))),
221
+ new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))),
222
+ );
223
+ }
224
+
225
+ /**
226
+ * Returns a list of tests to add to the existing list.
227
+ *
228
+ * @return array An array of tests
229
+ */
230
+ public function getTests()
231
+ {
232
+ return array(
233
+ new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')),
234
+ new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')),
235
+ new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')),
236
+ new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
237
+ new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')),
238
+ new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
239
+ new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')),
240
+ new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
241
+ new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')),
242
+ new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')),
243
+ new Twig_SimpleTest('empty', 'twig_test_empty'),
244
+ new Twig_SimpleTest('iterable', 'twig_test_iterable'),
245
+ );
246
+ }
247
+
248
+ /**
249
+ * Returns a list of operators to add to the existing list.
250
+ *
251
+ * @return array An array of operators
252
+ */
253
+ public function getOperators()
254
+ {
255
+ return array(
256
+ array(
257
+ 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'),
258
+ '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'),
259
+ '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'),
260
+ ),
261
+ array(
262
+ 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
263
+ 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
264
+ 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
265
+ 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
266
+ 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
267
+ '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
268
+ '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
269
+ '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
270
+ '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
271
+ '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
272
+ '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
273
+ 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
274
+ 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
275
+ 'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
276
+ 'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
277
+ 'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
278
+ '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
279
+ '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
280
+ '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
281
+ '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
282
+ '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
283
+ '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
284
+ '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
285
+ '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
286
+ 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
287
+ 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
288
+ '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
289
+ ),
290
+ );
291
+ }
292
+
293
+ public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
294
+ {
295
+ return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine());
296
+ }
297
+
298
+ public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node)
299
+ {
300
+ $stream = $parser->getStream();
301
+ $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
302
+ $class = $this->getTestNodeClass($parser, $name, $node->getLine());
303
+ $arguments = null;
304
+ if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
305
+ $arguments = $parser->getExpressionParser()->parseArguments(true);
306
+ }
307
+
308
+ return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
309
+ }
310
+
311
+ protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
312
+ {
313
+ $env = $parser->getEnvironment();
314
+ $testMap = $env->getTests();
315
+ $testName = null;
316
+ if (isset($testMap[$name])) {
317
+ $testName = $name;
318
+ } elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
319
+ // try 2-words tests
320
+ $name = $name.' '.$parser->getCurrentToken()->getValue();
321
+
322
+ if (isset($testMap[$name])) {
323
+ $parser->getStream()->next();
324
+
325
+ $testName = $name;
326
+ }
327
+ }
328
+
329
+ if (null === $testName) {
330
+ $message = sprintf('The test "%s" does not exist', $name);
331
+ if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) {
332
+ $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
333
+ }
334
+
335
+ throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
336
+ }
337
+
338
+ if ($testMap[$name] instanceof Twig_SimpleTest) {
339
+ return $testMap[$name]->getNodeClass();
340
+ }
341
+
342
+ return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test';
343
+ }
344
+
345
+ /**
346
+ * Returns the name of the extension.
347
+ *
348
+ * @return string The extension name
349
+ */
350
+ public function getName()
351
+ {
352
+ return 'core';
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Cycles over a value.
358
+ *
359
+ * @param ArrayAccess|array $values An array or an ArrayAccess instance
360
+ * @param integer $position The cycle position
361
+ *
362
+ * @return string The next value in the cycle
363
+ */
364
+ function twig_cycle($values, $position)
365
+ {
366
+ if (!is_array($values) && !$values instanceof ArrayAccess) {
367
+ return $values;
368
+ }
369
+
370
+ return $values[$position % count($values)];
371
+ }
372
+
373
+ /**
374
+ * Returns a random value depending on the supplied parameter type:
375
+ * - a random item from a Traversable or array
376
+ * - a random character from a string
377
+ * - a random integer between 0 and the integer parameter
378
+ *
379
+ * @param Twig_Environment $env A Twig_Environment instance
380
+ * @param Traversable|array|integer|string $values The values to pick a random item from
381
+ *
382
+ * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
383
+ *
384
+ * @return mixed A random value from the given sequence
385
+ */
386
+ function twig_random(Twig_Environment $env, $values = null)
387
+ {
388
+ if (null === $values) {
389
+ return mt_rand();
390
+ }
391
+
392
+ if (is_int($values) || is_float($values)) {
393
+ return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values);
394
+ }
395
+
396
+ if ($values instanceof Traversable) {
397
+ $values = iterator_to_array($values);
398
+ } elseif (is_string($values)) {
399
+ if ('' === $values) {
400
+ return '';
401
+ }
402
+ if (null !== $charset = $env->getCharset()) {
403
+ if ('UTF-8' != $charset) {
404
+ $values = twig_convert_encoding($values, 'UTF-8', $charset);
405
+ }
406
+
407
+ // unicode version of str_split()
408
+ // split at all positions, but not after the start and not before the end
409
+ $values = preg_split('/(?<!^)(?!$)/u', $values);
410
+
411
+ if ('UTF-8' != $charset) {
412
+ foreach ($values as $i => $value) {
413
+ $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8');
414
+ }
415
+ }
416
+ } else {
417
+ return $values[mt_rand(0, strlen($values) - 1)];
418
+ }
419
+ }
420
+
421
+ if (!is_array($values)) {
422
+ return $values;
423
+ }
424
+
425
+ if (0 === count($values)) {
426
+ throw new Twig_Error_Runtime('The random function cannot pick from an empty array.');
427
+ }
428
+
429
+ return $values[array_rand($values, 1)];
430
+ }
431
+
432
+ /**
433
+ * Converts a date to the given format.
434
+ *
435
+ * <pre>
436
+ * {{ post.published_at|date("m/d/Y") }}
437
+ * </pre>
438
+ *
439
+ * @param Twig_Environment $env A Twig_Environment instance
440
+ * @param DateTime|DateInterval|string $date A date
441
+ * @param string $format A format
442
+ * @param DateTimeZone|string $timezone A timezone
443
+ *
444
+ * @return string The formatted date
445
+ */
446
+ function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null)
447
+ {
448
+ if (null === $format) {
449
+ $formats = $env->getExtension('core')->getDateFormat();
450
+ $format = $date instanceof DateInterval ? $formats[1] : $formats[0];
451
+ }
452
+
453
+ if ($date instanceof DateInterval) {
454
+ return $date->format($format);
455
+ }
456
+
457
+ return twig_date_converter($env, $date, $timezone)->format($format);
458
+ }
459
+
460
+ /**
461
+ * Returns a new date object modified
462
+ *
463
+ * <pre>
464
+ * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
465
+ * </pre>
466
+ *
467
+ * @param Twig_Environment $env A Twig_Environment instance
468
+ * @param DateTime|string $date A date
469
+ * @param string $modifier A modifier string
470
+ *
471
+ * @return DateTime A new date object
472
+ */
473
+ function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
474
+ {
475
+ $date = twig_date_converter($env, $date, false);
476
+ $date->modify($modifier);
477
+
478
+ return $date;
479
+ }
480
+
481
+ /**
482
+ * Converts an input to a DateTime instance.
483
+ *
484
+ * <pre>
485
+ * {% if date(user.created_at) < date('+2days') %}
486
+ * {# do something #}
487
+ * {% endif %}
488
+ * </pre>
489
+ *
490
+ * @param Twig_Environment $env A Twig_Environment instance
491
+ * @param DateTime|string $date A date
492
+ * @param DateTimeZone|string $timezone A timezone
493
+ *
494
+ * @return DateTime A DateTime instance
495
+ */
496
+ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
497
+ {
498
+ // determine the timezone
499
+ if (!$timezone) {
500
+ $defaultTimezone = $env->getExtension('core')->getTimezone();
501
+ } elseif (!$timezone instanceof DateTimeZone) {
502
+ $defaultTimezone = new DateTimeZone($timezone);
503
+ } else {
504
+ $defaultTimezone = $timezone;
505
+ }
506
+
507
+ // immutable dates
508
+ if ($date instanceof DateTimeImmutable) {
509
+ return false !== $timezone ? $date->setTimezone($defaultTimezone) : $date;
510
+ }
511
+
512
+ if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
513
+ $date = clone $date;
514
+ if (false !== $timezone) {
515
+ $date->setTimezone($defaultTimezone);
516
+ }
517
+
518
+ return $date;
519
+ }
520
+
521
+ $asString = (string) $date;
522
+ if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) {
523
+ $date = '@'.$date;
524
+ }
525
+
526
+ $date = new DateTime($date, $defaultTimezone);
527
+ if (false !== $timezone) {
528
+ $date->setTimezone($defaultTimezone);
529
+ }
530
+
531
+ return $date;
532
+ }
533
+
534
+ /**
535
+ * Rounds a number.
536
+ *
537
+ * @param integer|float $value The value to round
538
+ * @param integer|float $precision The rounding precision
539
+ * @param string $method The method to use for rounding
540
+ *
541
+ * @return integer|float The rounded number
542
+ */
543
+ function twig_round($value, $precision = 0, $method = 'common')
544
+ {
545
+ if ('common' == $method) {
546
+ return round($value, $precision);
547
+ }
548
+
549
+ if ('ceil' != $method && 'floor' != $method) {
550
+ throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.');
551
+ }
552
+
553
+ return $method($value * pow(10, $precision)) / pow(10, $precision);
554
+ }
555
+
556
+ /**
557
+ * Number format filter.
558
+ *
559
+ * All of the formatting options can be left null, in that case the defaults will
560
+ * be used. Supplying any of the parameters will override the defaults set in the
561
+ * environment object.
562
+ *
563
+ * @param Twig_Environment $env A Twig_Environment instance
564
+ * @param mixed $number A float/int/string of the number to format
565
+ * @param integer $decimal The number of decimal points to display.
566
+ * @param string $decimalPoint The character(s) to use for the decimal point.
567
+ * @param string $thousandSep The character(s) to use for the thousands separator.
568
+ *
569
+ * @return string The formatted number
570
+ */
571
+ function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null)
572
+ {
573
+ $defaults = $env->getExtension('core')->getNumberFormat();
574
+ if (null === $decimal) {
575
+ $decimal = $defaults[0];
576
+ }
577
+
578
+ if (null === $decimalPoint) {
579
+ $decimalPoint = $defaults[1];
580
+ }
581
+
582
+ if (null === $thousandSep) {
583
+ $thousandSep = $defaults[2];
584
+ }
585
+
586
+ return number_format((float) $number, $decimal, $decimalPoint, $thousandSep);
587
+ }
588
+
589
+ /**
590
+ * URL encodes a string as a path segment or an array as a query string.
591
+ *
592
+ * @param string|array $url A URL or an array of query parameters
593
+ * @param Boolean $raw true to use rawurlencode() instead of urlencode
594
+ *
595
+ * @return string The URL encoded value
596
+ */
597
+ function twig_urlencode_filter($url, $raw = false)
598
+ {
599
+ if (is_array($url)) {
600
+ return http_build_query($url, '', '&');
601
+ }
602
+
603
+ if ($raw) {
604
+ return rawurlencode($url);
605
+ }
606
+
607
+ return urlencode($url);
608
+ }
609
+
610
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
611
+ /**
612
+ * JSON encodes a variable.
613
+ *
614
+ * @param mixed $value The value to encode.
615
+ * @param integer $options Not used on PHP 5.2.x
616
+ *
617
+ * @return mixed The JSON encoded value
618
+ */
619
+ function twig_jsonencode_filter($value, $options = 0)
620
+ {
621
+ if ($value instanceof Twig_Markup) {
622
+ $value = (string) $value;
623
+ } elseif (is_array($value)) {
624
+ array_walk_recursive($value, '_twig_markup2string');
625
+ }
626
+
627
+ return json_encode($value);
628
+ }
629
+ } else {
630
+ /**
631
+ * JSON encodes a variable.
632
+ *
633
+ * @param mixed $value The value to encode.
634
+ * @param integer $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
635
+ *
636
+ * @return mixed The JSON encoded value
637
+ */
638
+ function twig_jsonencode_filter($value, $options = 0)
639
+ {
640
+ if ($value instanceof Twig_Markup) {
641
+ $value = (string) $value;
642
+ } elseif (is_array($value)) {
643
+ array_walk_recursive($value, '_twig_markup2string');
644
+ }
645
+
646
+ return json_encode($value, $options);
647
+ }
648
+ }
649
+
650
+ function _twig_markup2string(&$value)
651
+ {
652
+ if ($value instanceof Twig_Markup) {
653
+ $value = (string) $value;
654
+ }
655
+ }
656
+
657
+ /**
658
+ * Merges an array with another one.
659
+ *
660
+ * <pre>
661
+ * {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
662
+ *
663
+ * {% set items = items|merge({ 'peugeot': 'car' }) %}
664
+ *
665
+ * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
666
+ * </pre>
667
+ *
668
+ * @param array $arr1 An array
669
+ * @param array $arr2 An array
670
+ *
671
+ * @return array The merged array
672
+ */
673
+ function twig_array_merge($arr1, $arr2)
674
+ {
675
+ if (!is_array($arr1) || !is_array($arr2)) {
676
+ throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
677
+ }
678
+
679
+ return array_merge($arr1, $arr2);
680
+ }
681
+
682
+ /**
683
+ * Slices a variable.
684
+ *
685
+ * @param Twig_Environment $env A Twig_Environment instance
686
+ * @param mixed $item A variable
687
+ * @param integer $start Start of the slice
688
+ * @param integer $length Size of the slice
689
+ * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array)
690
+ *
691
+ * @return mixed The sliced variable
692
+ */
693
+ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
694
+ {
695
+ if ($item instanceof Traversable) {
696
+ $item = iterator_to_array($item, false);
697
+ }
698
+
699
+ if (is_array($item)) {
700
+ return array_slice($item, $start, $length, $preserveKeys);
701
+ }
702
+
703
+ $item = (string) $item;
704
+
705
+ if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
706
+ return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
707
+ }
708
+
709
+ return null === $length ? substr($item, $start) : substr($item, $start, $length);
710
+ }
711
+
712
+ /**
713
+ * Returns the first element of the item.
714
+ *
715
+ * @param Twig_Environment $env A Twig_Environment instance
716
+ * @param mixed $item A variable
717
+ *
718
+ * @return mixed The first element of the item
719
+ */
720
+ function twig_first(Twig_Environment $env, $item)
721
+ {
722
+ $elements = twig_slice($env, $item, 0, 1, false);
723
+
724
+ return is_string($elements) ? $elements : current($elements);
725
+ }
726
+
727
+ /**
728
+ * Returns the last element of the item.
729
+ *
730
+ * @param Twig_Environment $env A Twig_Environment instance
731
+ * @param mixed $item A variable
732
+ *
733
+ * @return mixed The last element of the item
734
+ */
735
+ function twig_last(Twig_Environment $env, $item)
736
+ {
737
+ $elements = twig_slice($env, $item, -1, 1, false);
738
+
739
+ return is_string($elements) ? $elements : current($elements);
740
+ }
741
+
742
+ /**
743
+ * Joins the values to a string.
744
+ *
745
+ * The separator between elements is an empty string per default, you can define it with the optional parameter.
746
+ *
747
+ * <pre>
748
+ * {{ [1, 2, 3]|join('|') }}
749
+ * {# returns 1|2|3 #}
750
+ *
751
+ * {{ [1, 2, 3]|join }}
752
+ * {# returns 123 #}
753
+ * </pre>
754
+ *
755
+ * @param array $value An array
756
+ * @param string $glue The separator
757
+ *
758
+ * @return string The concatenated string
759
+ */
760
+ function twig_join_filter($value, $glue = '')
761
+ {
762
+ if ($value instanceof Traversable) {
763
+ $value = iterator_to_array($value, false);
764
+ }
765
+
766
+ return implode($glue, (array) $value);
767
+ }
768
+
769
+ /**
770
+ * Splits the string into an array.
771
+ *
772
+ * <pre>
773
+ * {{ "one,two,three"|split(',') }}
774
+ * {# returns [one, two, three] #}
775
+ *
776
+ * {{ "one,two,three,four,five"|split(',', 3) }}
777
+ * {# returns [one, two, "three,four,five"] #}
778
+ *
779
+ * {{ "123"|split('') }}
780
+ * {# returns [1, 2, 3] #}
781
+ *
782
+ * {{ "aabbcc"|split('', 2) }}
783
+ * {# returns [aa, bb, cc] #}
784
+ * </pre>
785
+ *
786
+ * @param string $value A string
787
+ * @param string $delimiter The delimiter
788
+ * @param integer $limit The limit
789
+ *
790
+ * @return array The split string as an array
791
+ */
792
+ function twig_split_filter($value, $delimiter, $limit = null)
793
+ {
794
+ if (empty($delimiter)) {
795
+ return str_split($value, null === $limit ? 1 : $limit);
796
+ }
797
+
798
+ return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
799
+ }
800
+
801
+ // The '_default' filter is used internally to avoid using the ternary operator
802
+ // which costs a lot for big contexts (before PHP 5.4). So, on average,
803
+ // a function call is cheaper.
804
+ function _twig_default_filter($value, $default = '')
805
+ {
806
+ if (twig_test_empty($value)) {
807
+ return $default;
808
+ }
809
+
810
+ return $value;
811
+ }
812
+
813
+ /**
814
+ * Returns the keys for the given array.
815
+ *
816
+ * It is useful when you want to iterate over the keys of an array:
817
+ *
818
+ * <pre>
819
+ * {% for key in array|keys %}
820
+ * {# ... #}
821
+ * {% endfor %}
822
+ * </pre>
823
+ *
824
+ * @param array $array An array
825
+ *
826
+ * @return array The keys
827
+ */
828
+ function twig_get_array_keys_filter($array)
829
+ {
830
+ if (is_object($array) && $array instanceof Traversable) {
831
+ return array_keys(iterator_to_array($array));
832
+ }
833
+
834
+ if (!is_array($array)) {
835
+ return array();
836
+ }
837
+
838
+ return array_keys($array);
839
+ }
840
+
841
+ /**
842
+ * Reverses a variable.
843
+ *
844
+ * @param Twig_Environment $env A Twig_Environment instance
845
+ * @param array|Traversable|string $item An array, a Traversable instance, or a string
846
+ * @param Boolean $preserveKeys Whether to preserve key or not
847
+ *
848
+ * @return mixed The reversed input
849
+ */
850
+ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
851
+ {
852
+ if (is_object($item) && $item instanceof Traversable) {
853
+ return array_reverse(iterator_to_array($item), $preserveKeys);
854
+ }
855
+
856
+ if (is_array($item)) {
857
+ return array_reverse($item, $preserveKeys);
858
+ }
859
+
860
+ if (null !== $charset = $env->getCharset()) {
861
+ $string = (string) $item;
862
+
863
+ if ('UTF-8' != $charset) {
864
+ $item = twig_convert_encoding($string, 'UTF-8', $charset);
865
+ }
866
+
867
+ preg_match_all('/./us', $item, $matches);
868
+
869
+ $string = implode('', array_reverse($matches[0]));
870
+
871
+ if ('UTF-8' != $charset) {
872
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
873
+ }
874
+
875
+ return $string;
876
+ }
877
+
878
+ return strrev((string) $item);
879
+ }
880
+
881
+ /**
882
+ * Sorts an array.
883
+ *
884
+ * @param array $array An array
885
+ */
886
+ function twig_sort_filter($array)
887
+ {
888
+ asort($array);
889
+
890
+ return $array;
891
+ }
892
+
893
+ /* used internally */
894
+ function twig_in_filter($value, $compare)
895
+ {
896
+ if (is_array($compare)) {
897
+ return in_array($value, $compare, is_object($value));
898
+ } elseif (is_string($compare)) {
899
+ if (!strlen($value)) {
900
+ return empty($compare);
901
+ }
902
+
903
+ return false !== strpos($compare, (string) $value);
904
+ } elseif ($compare instanceof Traversable) {
905
+ return in_array($value, iterator_to_array($compare, false), is_object($value));
906
+ }
907
+
908
+ return false;
909
+ }
910
+
911
+ /**
912
+ * Escapes a string.
913
+ *
914
+ * @param Twig_Environment $env A Twig_Environment instance
915
+ * @param string $string The value to be escaped
916
+ * @param string $strategy The escaping strategy
917
+ * @param string $charset The charset
918
+ * @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
919
+ */
920
+ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
921
+ {
922
+ if ($autoescape && $string instanceof Twig_Markup) {
923
+ return $string;
924
+ }
925
+
926
+ if (!is_string($string)) {
927
+ if (is_object($string) && method_exists($string, '__toString')) {
928
+ $string = (string) $string;
929
+ } else {
930
+ return $string;
931
+ }
932
+ }
933
+
934
+ if (null === $charset) {
935
+ $charset = $env->getCharset();
936
+ }
937
+
938
+ switch ($strategy) {
939
+ case 'html':
940
+ // see http://php.net/htmlspecialchars
941
+
942
+ // Using a static variable to avoid initializing the array
943
+ // each time the function is called. Moving the declaration on the
944
+ // top of the function slow downs other escaping strategies.
945
+ static $htmlspecialcharsCharsets;
946
+
947
+ if (null === $htmlspecialcharsCharsets) {
948
+ if ('hiphop' === substr(PHP_VERSION, -6)) {
949
+ $htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true);
950
+ } else {
951
+ $htmlspecialcharsCharsets = array(
952
+ 'ISO-8859-1' => true, 'ISO8859-1' => true,
953
+ 'ISO-8859-15' => true, 'ISO8859-15' => true,
954
+ 'utf-8' => true, 'UTF-8' => true,
955
+ 'CP866' => true, 'IBM866' => true, '866' => true,
956
+ 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true,
957
+ '1251' => true,
958
+ 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true,
959
+ 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true,
960
+ 'BIG5' => true, '950' => true,
961
+ 'GB2312' => true, '936' => true,
962
+ 'BIG5-HKSCS' => true,
963
+ 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true,
964
+ 'EUC-JP' => true, 'EUCJP' => true,
965
+ 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true,
966
+ );
967
+ }
968
+ }
969
+
970
+ if (isset($htmlspecialcharsCharsets[$charset])) {
971
+ return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
972
+ }
973
+
974
+ if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) {
975
+ // cache the lowercase variant for future iterations
976
+ $htmlspecialcharsCharsets[$charset] = true;
977
+
978
+ return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset);
979
+ }
980
+
981
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
982
+ $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
983
+
984
+ return twig_convert_encoding($string, $charset, 'UTF-8');
985
+
986
+ case 'js':
987
+ // escape all non-alphanumeric characters
988
+ // into their \xHH or \uHHHH representations
989
+ if ('UTF-8' != $charset) {
990
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
991
+ }
992
+
993
+ if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
994
+ throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
995
+ }
996
+
997
+ $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string);
998
+
999
+ if ('UTF-8' != $charset) {
1000
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
1001
+ }
1002
+
1003
+ return $string;
1004
+
1005
+ case 'css':
1006
+ if ('UTF-8' != $charset) {
1007
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
1008
+ }
1009
+
1010
+ if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
1011
+ throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
1012
+ }
1013
+
1014
+ $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string);
1015
+
1016
+ if ('UTF-8' != $charset) {
1017
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
1018
+ }
1019
+
1020
+ return $string;
1021
+
1022
+ case 'html_attr':
1023
+ if ('UTF-8' != $charset) {
1024
+ $string = twig_convert_encoding($string, 'UTF-8', $charset);
1025
+ }
1026
+
1027
+ if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) {
1028
+ throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.');
1029
+ }
1030
+
1031
+ $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string);
1032
+
1033
+ if ('UTF-8' != $charset) {
1034
+ $string = twig_convert_encoding($string, $charset, 'UTF-8');
1035
+ }
1036
+
1037
+ return $string;
1038
+
1039
+ case 'url':
1040
+ // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.*
1041
+ // at that point however PHP 5.2.* support can be removed
1042
+ if (PHP_VERSION < '5.3.0') {
1043
+ return str_replace('%7E', '~', rawurlencode($string));
1044
+ }
1045
+
1046
+ return rawurlencode($string);
1047
+
1048
+ default:
1049
+ static $escapers;
1050
+
1051
+ if (null === $escapers) {
1052
+ $escapers = $env->getExtension('core')->getEscapers();
1053
+ }
1054
+
1055
+ if (isset($escapers[$strategy])) {
1056
+ return call_user_func($escapers[$strategy], $env, $string, $charset);
1057
+ }
1058
+
1059
+ $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers)));
1060
+
1061
+ throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies));
1062
+ }
1063
+ }
1064
+
1065
+ /* used internally */
1066
+ function twig_escape_filter_is_safe(Twig_Node $filterArgs)
1067
+ {
1068
+ foreach ($filterArgs as $arg) {
1069
+ if ($arg instanceof Twig_Node_Expression_Constant) {
1070
+ return array($arg->getAttribute('value'));
1071
+ }
1072
+
1073
+ return array();
1074
+ }
1075
+
1076
+ return array('html');
1077
+ }
1078
+
1079
+ if (function_exists('mb_convert_encoding')) {
1080
+ function twig_convert_encoding($string, $to, $from)
1081
+ {
1082
+ return mb_convert_encoding($string, $to, $from);
1083
+ }
1084
+ } elseif (function_exists('iconv')) {
1085
+ function twig_convert_encoding($string, $to, $from)
1086
+ {
1087
+ return iconv($from, $to, $string);
1088
+ }
1089
+ } else {
1090
+ function twig_convert_encoding($string, $to, $from)
1091
+ {
1092
+ throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
1093
+ }
1094
+ }
1095
+
1096
+ function _twig_escape_js_callback($matches)
1097
+ {
1098
+ $char = $matches[0];
1099
+
1100
+ // \xHH
1101
+ if (!isset($char[1])) {
1102
+ return '\\x'.strtoupper(substr('00'.bin2hex($char), -2));
1103
+ }
1104
+
1105
+ // \uHHHH
1106
+ $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1107
+
1108
+ return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
1109
+ }
1110
+
1111
+ function _twig_escape_css_callback($matches)
1112
+ {
1113
+ $char = $matches[0];
1114
+
1115
+ // \xHH
1116
+ if (!isset($char[1])) {
1117
+ $hex = ltrim(strtoupper(bin2hex($char)), '0');
1118
+ if (0 === strlen($hex)) {
1119
+ $hex = '0';
1120
+ }
1121
+
1122
+ return '\\'.$hex.' ';
1123
+ }
1124
+
1125
+ // \uHHHH
1126
+ $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8');
1127
+
1128
+ return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
1129
+ }
1130
+
1131
+ /**
1132
+ * This function is adapted from code coming from Zend Framework.
1133
+ *
1134
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
1135
+ * @license http://framework.zend.com/license/new-bsd New BSD License
1136
+ */
1137
+ function _twig_escape_html_attr_callback($matches)
1138
+ {
1139
+ /*
1140
+ * While HTML supports far more named entities, the lowest common denominator
1141
+ * has become HTML5's XML Serialisation which is restricted to the those named
1142
+ * entities that XML supports. Using HTML entities would result in this error:
1143
+ * XML Parsing Error: undefined entity
1144
+ */
1145
+ static $entityMap = array(
1146
+ 34 => 'quot', /* quotation mark */
1147
+ 38 => 'amp', /* ampersand */
1148
+ 60 => 'lt', /* less-than sign */
1149
+ 62 => 'gt', /* greater-than sign */
1150
+ );
1151
+
1152
+ $chr = $matches[0];
1153
+ $ord = ord($chr);
1154
+
1155
+ /**
1156
+ * The following replaces characters undefined in HTML with the
1157
+ * hex entity for the Unicode replacement character.
1158
+ */
1159
+ if (($ord <= 0x1f && $chr != "\t" && $chr != "\n" && $chr != "\r") || ($ord >= 0x7f && $ord <= 0x9f)) {
1160
+ return '&#xFFFD;';
1161
+ }
1162
+
1163
+ /**
1164
+ * Check if the current character to escape has a name entity we should
1165
+ * replace it with while grabbing the hex value of the character.
1166
+ */
1167
+ if (strlen($chr) == 1) {
1168
+ $hex = strtoupper(substr('00'.bin2hex($chr), -2));
1169
+ } else {
1170
+ $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8');
1171
+ $hex = strtoupper(substr('0000'.bin2hex($chr), -4));
1172
+ }
1173
+
1174
+ $int = hexdec($hex);
1175
+ if (array_key_exists($int, $entityMap)) {
1176
+ return sprintf('&%s;', $entityMap[$int]);
1177
+ }
1178
+
1179
+ /**
1180
+ * Per OWASP recommendations, we'll use hex entities for any other
1181
+ * characters where a named entity does not exist.
1182
+ */
1183
+
1184
+ return sprintf('&#x%s;', $hex);
1185
+ }
1186
+
1187
+ // add multibyte extensions if possible
1188
+ if (function_exists('mb_get_info')) {
1189
+ /**
1190
+ * Returns the length of a variable.
1191
+ *
1192
+ * @param Twig_Environment $env A Twig_Environment instance
1193
+ * @param mixed $thing A variable
1194
+ *
1195
+ * @return integer The length of the value
1196
+ */
1197
+ function twig_length_filter(Twig_Environment $env, $thing)
1198
+ {
1199
+ return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
1200
+ }
1201
+
1202
+ /**
1203
+ * Converts a string to uppercase.
1204
+ *
1205
+ * @param Twig_Environment $env A Twig_Environment instance
1206
+ * @param string $string A string
1207
+ *
1208
+ * @return string The uppercased string
1209
+ */
1210
+ function twig_upper_filter(Twig_Environment $env, $string)
1211
+ {
1212
+ if (null !== ($charset = $env->getCharset())) {
1213
+ return mb_strtoupper($string, $charset);
1214
+ }
1215
+
1216
+ return strtoupper($string);
1217
+ }
1218
+
1219
+ /**
1220
+ * Converts a string to lowercase.
1221
+ *
1222
+ * @param Twig_Environment $env A Twig_Environment instance
1223
+ * @param string $string A string
1224
+ *
1225
+ * @return string The lowercased string
1226
+ */
1227
+ function twig_lower_filter(Twig_Environment $env, $string)
1228
+ {
1229
+ if (null !== ($charset = $env->getCharset())) {
1230
+ return mb_strtolower($string, $charset);
1231
+ }
1232
+
1233
+ return strtolower($string);
1234
+ }
1235
+
1236
+ /**
1237
+ * Returns a titlecased string.
1238
+ *
1239
+ * @param Twig_Environment $env A Twig_Environment instance
1240
+ * @param string $string A string
1241
+ *
1242
+ * @return string The titlecased string
1243
+ */
1244
+ function twig_title_string_filter(Twig_Environment $env, $string)
1245
+ {
1246
+ if (null !== ($charset = $env->getCharset())) {
1247
+ return mb_convert_case($string, MB_CASE_TITLE, $charset);
1248
+ }
1249
+
1250
+ return ucwords(strtolower($string));
1251
+ }
1252
+
1253
+ /**
1254
+ * Returns a capitalized string.
1255
+ *
1256
+ * @param Twig_Environment $env A Twig_Environment instance
1257
+ * @param string $string A string
1258
+ *
1259
+ * @return string The capitalized string
1260
+ */
1261
+ function twig_capitalize_string_filter(Twig_Environment $env, $string)
1262
+ {
1263
+ if (null !== ($charset = $env->getCharset())) {
1264
+ return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
1265
+ mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
1266
+ }
1267
+
1268
+ return ucfirst(strtolower($string));
1269
+ }
1270
+ }
1271
+ // and byte fallback
1272
+ else {
1273
+ /**
1274
+ * Returns the length of a variable.
1275
+ *
1276
+ * @param Twig_Environment $env A Twig_Environment instance
1277
+ * @param mixed $thing A variable
1278
+ *
1279
+ * @return integer The length of the value
1280
+ */
1281
+ function twig_length_filter(Twig_Environment $env, $thing)
1282
+ {
1283
+ return is_scalar($thing) ? strlen($thing) : count($thing);
1284
+ }
1285
+
1286
+ /**
1287
+ * Returns a titlecased string.
1288
+ *
1289
+ * @param Twig_Environment $env A Twig_Environment instance
1290
+ * @param string $string A string
1291
+ *
1292
+ * @return string The titlecased string
1293
+ */
1294
+ function twig_title_string_filter(Twig_Environment $env, $string)
1295
+ {
1296
+ return ucwords(strtolower($string));
1297
+ }
1298
+
1299
+ /**
1300
+ * Returns a capitalized string.
1301
+ *
1302
+ * @param Twig_Environment $env A Twig_Environment instance
1303
+ * @param string $string A string
1304
+ *
1305
+ * @return string The capitalized string
1306
+ */
1307
+ function twig_capitalize_string_filter(Twig_Environment $env, $string)
1308
+ {
1309
+ return ucfirst(strtolower($string));
1310
+ }
1311
+ }
1312
+
1313
+ /* used internally */
1314
+ function twig_ensure_traversable($seq)
1315
+ {
1316
+ if ($seq instanceof Traversable || is_array($seq)) {
1317
+ return $seq;
1318
+ }
1319
+
1320
+ return array();
1321
+ }
1322
+
1323
+ /**
1324
+ * Checks if a variable is empty.
1325
+ *
1326
+ * <pre>
1327
+ * {# evaluates to true if the foo variable is null, false, or the empty string #}
1328
+ * {% if foo is empty %}
1329
+ * {# ... #}
1330
+ * {% endif %}
1331
+ * </pre>
1332
+ *
1333
+ * @param mixed $value A variable
1334
+ *
1335
+ * @return Boolean true if the value is empty, false otherwise
1336
+ */
1337
+ function twig_test_empty($value)
1338
+ {
1339
+ if ($value instanceof Countable) {
1340
+ return 0 == count($value);
1341
+ }
1342
+
1343
+ return '' === $value || false === $value || null === $value || array() === $value;
1344
+ }
1345
+
1346
+ /**
1347
+ * Checks if a variable is traversable.
1348
+ *
1349
+ * <pre>
1350
+ * {# evaluates to true if the foo variable is an array or a traversable object #}
1351
+ * {% if foo is traversable %}
1352
+ * {# ... #}
1353
+ * {% endif %}
1354
+ * </pre>
1355
+ *
1356
+ * @param mixed $value A variable
1357
+ *
1358
+ * @return Boolean true if the value is traversable
1359
+ */
1360
+ function twig_test_iterable($value)
1361
+ {
1362
+ return $value instanceof Traversable || is_array($value);
1363
+ }
1364
+
1365
+ /**
1366
+ * Renders a template.
1367
+ *
1368
+ * @param string|array $template The template to render or an array of templates to try consecutively
1369
+ * @param array $variables The variables to pass to the template
1370
+ * @param Boolean $with_context Whether to pass the current context variables or not
1371
+ * @param Boolean $ignore_missing Whether to ignore missing templates or not
1372
+ * @param Boolean $sandboxed Whether to sandbox the template or not
1373
+ *
1374
+ * @return string The rendered template
1375
+ */
1376
+ function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
1377
+ {
1378
+ $alreadySandboxed = false;
1379
+ $sandbox = null;
1380
+ if ($withContext) {
1381
+ $variables = array_merge($context, $variables);
1382
+ }
1383
+
1384
+ if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) {
1385
+ $sandbox = $env->getExtension('sandbox');
1386
+ if (!$alreadySandboxed = $sandbox->isSandboxed()) {
1387
+ $sandbox->enableSandbox();
1388
+ }
1389
+ }
1390
+
1391
+ try {
1392
+ return $env->resolveTemplate($template)->render($variables);
1393
+ } catch (Twig_Error_Loader $e) {
1394
+ if (!$ignoreMissing) {
1395
+ throw $e;
1396
+ }
1397
+ }
1398
+
1399
+ if ($isSandboxed && !$alreadySandboxed) {
1400
+ $sandbox->disableSandbox();
1401
+ }
1402
+ }
1403
+
1404
+ /**
1405
+ * Returns a template content without rendering it.
1406
+ *
1407
+ * @param string $name The template name
1408
+ *
1409
+ * @return string The template source
1410
+ */
1411
+ function twig_source(Twig_Environment $env, $name)
1412
+ {
1413
+ return $env->getLoader()->getSource($name);
1414
+ }
1415
+
1416
+ /**
1417
+ * Provides the ability to get constants from instances as well as class/global constants.
1418
+ *
1419
+ * @param string $constant The name of the constant
1420
+ * @param null|object $object The object to get the constant from
1421
+ *
1422
+ * @return string
1423
+ */
1424
+ function twig_constant($constant, $object = null)
1425
+ {
1426
+ if (null !== $object) {
1427
+ $constant = get_class($object).'::'.$constant;
1428
+ }
1429
+
1430
+ return constant($constant);
1431
+ }
1432
+
1433
+ /**
1434
+ * Batches item.
1435
+ *
1436
+ * @param array $items An array of items
1437
+ * @param integer $size The size of the batch
1438
+ * @param mixed $fill A value used to fill missing items
1439
+ *
1440
+ * @return array
1441
+ */
1442
+ function twig_array_batch($items, $size, $fill = null)
1443
+ {
1444
+ if ($items instanceof Traversable) {
1445
+ $items = iterator_to_array($items, false);
1446
+ }
1447
+
1448
+ $size = ceil($size);
1449
+
1450
+ $result = array_chunk($items, $size, true);
1451
+
1452
+ if (null !== $fill) {
1453
+ $last = count($result) - 1;
1454
+ if ($fillCount = $size - count($result[$last])) {
1455
+ $result[$last] = array_merge(
1456
+ $result[$last],
1457
+ array_fill(0, $fillCount, $fill)
1458
+ );
1459
+ }
1460
+ }
1461
+
1462
+ return $result;
1463
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/Debug.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Debug extends Twig_Extension
12
+ {
13
+ /**
14
+ * Returns a list of global functions to add to the existing list.
15
+ *
16
+ * @return array An array of global functions
17
+ */
18
+ public function getFunctions()
19
+ {
20
+ // dump is safe if var_dump is overridden by xdebug
21
+ $isDumpOutputHtmlSafe = extension_loaded('xdebug')
22
+ // false means that it was not set (and the default is on) or it explicitly enabled
23
+ && (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
24
+ // false means that it was not set (and the default is on) or it explicitly enabled
25
+ // xdebug.overload_var_dump produces HTML only when html_errors is also enabled
26
+ && (false === ini_get('html_errors') || ini_get('html_errors'))
27
+ || 'cli' === php_sapi_name()
28
+ ;
29
+
30
+ return array(
31
+ new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
32
+ );
33
+ }
34
+
35
+ /**
36
+ * Returns the name of the extension.
37
+ *
38
+ * @return string The extension name
39
+ */
40
+ public function getName()
41
+ {
42
+ return 'debug';
43
+ }
44
+ }
45
+
46
+ function twig_var_dump(Twig_Environment $env, $context)
47
+ {
48
+ if (!$env->isDebug()) {
49
+ return;
50
+ }
51
+
52
+ ob_start();
53
+
54
+ $count = func_num_args();
55
+ if (2 === $count) {
56
+ $vars = array();
57
+ foreach ($context as $key => $value) {
58
+ if (!$value instanceof Twig_Template) {
59
+ $vars[$key] = $value;
60
+ }
61
+ }
62
+
63
+ var_dump($vars);
64
+ } else {
65
+ for ($i = 2; $i < $count; $i++) {
66
+ var_dump(func_get_arg($i));
67
+ }
68
+ }
69
+
70
+ return ob_get_clean();
71
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/Escaper.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Escaper extends Twig_Extension
12
+ {
13
+ protected $defaultStrategy;
14
+
15
+ public function __construct($defaultStrategy = 'html')
16
+ {
17
+ $this->setDefaultStrategy($defaultStrategy);
18
+ }
19
+
20
+ /**
21
+ * Returns the token parser instances to add to the existing list.
22
+ *
23
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
24
+ */
25
+ public function getTokenParsers()
26
+ {
27
+ return array(new Twig_TokenParser_AutoEscape());
28
+ }
29
+
30
+ /**
31
+ * Returns the node visitor instances to add to the existing list.
32
+ *
33
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
34
+ */
35
+ public function getNodeVisitors()
36
+ {
37
+ return array(new Twig_NodeVisitor_Escaper());
38
+ }
39
+
40
+ /**
41
+ * Returns a list of filters to add to the existing list.
42
+ *
43
+ * @return array An array of filters
44
+ */
45
+ public function getFilters()
46
+ {
47
+ return array(
48
+ new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Sets the default strategy to use when not defined by the user.
54
+ *
55
+ * The strategy can be a valid PHP callback that takes the template
56
+ * "filename" as an argument and returns the strategy to use.
57
+ *
58
+ * @param mixed $defaultStrategy An escaping strategy
59
+ */
60
+ public function setDefaultStrategy($defaultStrategy)
61
+ {
62
+ // for BC
63
+ if (true === $defaultStrategy) {
64
+ $defaultStrategy = 'html';
65
+ }
66
+
67
+ $this->defaultStrategy = $defaultStrategy;
68
+ }
69
+
70
+ /**
71
+ * Gets the default strategy to use when not defined by the user.
72
+ *
73
+ * @param string $filename The template "filename"
74
+ *
75
+ * @return string The default strategy to use for the template
76
+ */
77
+ public function getDefaultStrategy($filename)
78
+ {
79
+ // disable string callables to avoid calling a function named html or js,
80
+ // or any other upcoming escaping strategy
81
+ if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
82
+ return call_user_func($this->defaultStrategy, $filename);
83
+ }
84
+
85
+ return $this->defaultStrategy;
86
+ }
87
+
88
+ /**
89
+ * Returns the name of the extension.
90
+ *
91
+ * @return string The extension name
92
+ */
93
+ public function getName()
94
+ {
95
+ return 'escaper';
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Marks a variable as being safe.
101
+ *
102
+ * @param string $string A PHP variable
103
+ */
104
+ function twig_raw_filter($string)
105
+ {
106
+ return $string;
107
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/Optimizer.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Optimizer extends Twig_Extension
12
+ {
13
+ protected $optimizers;
14
+
15
+ public function __construct($optimizers = -1)
16
+ {
17
+ $this->optimizers = $optimizers;
18
+ }
19
+
20
+ /**
21
+ * {@inheritdoc}
22
+ */
23
+ public function getNodeVisitors()
24
+ {
25
+ return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
26
+ }
27
+
28
+ /**
29
+ * {@inheritdoc}
30
+ */
31
+ public function getName()
32
+ {
33
+ return 'optimizer';
34
+ }
35
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/Sandbox.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_Sandbox extends Twig_Extension
12
+ {
13
+ protected $sandboxedGlobally;
14
+ protected $sandboxed;
15
+ protected $policy;
16
+
17
+ public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
18
+ {
19
+ $this->policy = $policy;
20
+ $this->sandboxedGlobally = $sandboxed;
21
+ }
22
+
23
+ /**
24
+ * Returns the token parser instances to add to the existing list.
25
+ *
26
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
27
+ */
28
+ public function getTokenParsers()
29
+ {
30
+ return array(new Twig_TokenParser_Sandbox());
31
+ }
32
+
33
+ /**
34
+ * Returns the node visitor instances to add to the existing list.
35
+ *
36
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
37
+ */
38
+ public function getNodeVisitors()
39
+ {
40
+ return array(new Twig_NodeVisitor_Sandbox());
41
+ }
42
+
43
+ public function enableSandbox()
44
+ {
45
+ $this->sandboxed = true;
46
+ }
47
+
48
+ public function disableSandbox()
49
+ {
50
+ $this->sandboxed = false;
51
+ }
52
+
53
+ public function isSandboxed()
54
+ {
55
+ return $this->sandboxedGlobally || $this->sandboxed;
56
+ }
57
+
58
+ public function isSandboxedGlobally()
59
+ {
60
+ return $this->sandboxedGlobally;
61
+ }
62
+
63
+ public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
64
+ {
65
+ $this->policy = $policy;
66
+ }
67
+
68
+ public function getSecurityPolicy()
69
+ {
70
+ return $this->policy;
71
+ }
72
+
73
+ public function checkSecurity($tags, $filters, $functions)
74
+ {
75
+ if ($this->isSandboxed()) {
76
+ $this->policy->checkSecurity($tags, $filters, $functions);
77
+ }
78
+ }
79
+
80
+ public function checkMethodAllowed($obj, $method)
81
+ {
82
+ if ($this->isSandboxed()) {
83
+ $this->policy->checkMethodAllowed($obj, $method);
84
+ }
85
+ }
86
+
87
+ public function checkPropertyAllowed($obj, $method)
88
+ {
89
+ if ($this->isSandboxed()) {
90
+ $this->policy->checkPropertyAllowed($obj, $method);
91
+ }
92
+ }
93
+
94
+ public function ensureToStringAllowed($obj)
95
+ {
96
+ if (is_object($obj)) {
97
+ $this->policy->checkMethodAllowed($obj, '__toString');
98
+ }
99
+
100
+ return $obj;
101
+ }
102
+
103
+ /**
104
+ * Returns the name of the extension.
105
+ *
106
+ * @return string The extension name
107
+ */
108
+ public function getName()
109
+ {
110
+ return 'sandbox';
111
+ }
112
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/Staging.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Internal class.
14
+ *
15
+ * This class is used by Twig_Environment as a staging area and must not be used directly.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ */
19
+ class Twig_Extension_Staging extends Twig_Extension
20
+ {
21
+ protected $functions = array();
22
+ protected $filters = array();
23
+ protected $visitors = array();
24
+ protected $tokenParsers = array();
25
+ protected $globals = array();
26
+ protected $tests = array();
27
+
28
+ public function addFunction($name, $function)
29
+ {
30
+ $this->functions[$name] = $function;
31
+ }
32
+
33
+ /**
34
+ * {@inheritdoc}
35
+ */
36
+ public function getFunctions()
37
+ {
38
+ return $this->functions;
39
+ }
40
+
41
+ public function addFilter($name, $filter)
42
+ {
43
+ $this->filters[$name] = $filter;
44
+ }
45
+
46
+ /**
47
+ * {@inheritdoc}
48
+ */
49
+ public function getFilters()
50
+ {
51
+ return $this->filters;
52
+ }
53
+
54
+ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
55
+ {
56
+ $this->visitors[] = $visitor;
57
+ }
58
+
59
+ /**
60
+ * {@inheritdoc}
61
+ */
62
+ public function getNodeVisitors()
63
+ {
64
+ return $this->visitors;
65
+ }
66
+
67
+ public function addTokenParser(Twig_TokenParserInterface $parser)
68
+ {
69
+ $this->tokenParsers[] = $parser;
70
+ }
71
+
72
+ /**
73
+ * {@inheritdoc}
74
+ */
75
+ public function getTokenParsers()
76
+ {
77
+ return $this->tokenParsers;
78
+ }
79
+
80
+ public function addGlobal($name, $value)
81
+ {
82
+ $this->globals[$name] = $value;
83
+ }
84
+
85
+ /**
86
+ * {@inheritdoc}
87
+ */
88
+ public function getGlobals()
89
+ {
90
+ return $this->globals;
91
+ }
92
+
93
+ public function addTest($name, $test)
94
+ {
95
+ $this->tests[$name] = $test;
96
+ }
97
+
98
+ /**
99
+ * {@inheritdoc}
100
+ */
101
+ public function getTests()
102
+ {
103
+ return $this->tests;
104
+ }
105
+
106
+ /**
107
+ * {@inheritdoc}
108
+ */
109
+ public function getName()
110
+ {
111
+ return 'staging';
112
+ }
113
+ }
vendor/vendor/twig/twig/lib/Twig/Extension/StringLoader.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Extension_StringLoader extends Twig_Extension
12
+ {
13
+ /**
14
+ * {@inheritdoc}
15
+ */
16
+ public function getFunctions()
17
+ {
18
+ return array(
19
+ new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
20
+ );
21
+ }
22
+
23
+ /**
24
+ * {@inheritdoc}
25
+ */
26
+ public function getName()
27
+ {
28
+ return 'string_loader';
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Loads a template from a string.
34
+ *
35
+ * <pre>
36
+ * {{ include(template_from_string("Hello {{ name }}")) }}
37
+ * </pre>
38
+ *
39
+ * @param Twig_Environment $env A Twig_Environment instance
40
+ * @param string $template A template as a string
41
+ *
42
+ * @return Twig_Template A Twig_Template instance
43
+ */
44
+ function twig_template_from_string(Twig_Environment $env, $template)
45
+ {
46
+ $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
47
+
48
+ $loader = new Twig_Loader_Chain(array(
49
+ new Twig_Loader_Array(array($name => $template)),
50
+ $current = $env->getLoader(),
51
+ ));
52
+
53
+ $env->setLoader($loader);
54
+ try {
55
+ $template = $env->loadTemplate($name);
56
+ } catch (Exception $e) {
57
+ $env->setLoader($current);
58
+
59
+ throw $e;
60
+ }
61
+ $env->setLoader($current);
62
+
63
+ return $template;
64
+ }
vendor/vendor/twig/twig/lib/Twig/ExtensionInterface.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by extension classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_ExtensionInterface
18
+ {
19
+ /**
20
+ * Initializes the runtime environment.
21
+ *
22
+ * This is where you can load some file that contains filter functions for instance.
23
+ *
24
+ * @param Twig_Environment $environment The current Twig_Environment instance
25
+ */
26
+ public function initRuntime(Twig_Environment $environment);
27
+
28
+ /**
29
+ * Returns the token parser instances to add to the existing list.
30
+ *
31
+ * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
32
+ */
33
+ public function getTokenParsers();
34
+
35
+ /**
36
+ * Returns the node visitor instances to add to the existing list.
37
+ *
38
+ * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
39
+ */
40
+ public function getNodeVisitors();
41
+
42
+ /**
43
+ * Returns a list of filters to add to the existing list.
44
+ *
45
+ * @return array An array of filters
46
+ */
47
+ public function getFilters();
48
+
49
+ /**
50
+ * Returns a list of tests to add to the existing list.
51
+ *
52
+ * @return array An array of tests
53
+ */
54
+ public function getTests();
55
+
56
+ /**
57
+ * Returns a list of functions to add to the existing list.
58
+ *
59
+ * @return array An array of functions
60
+ */
61
+ public function getFunctions();
62
+
63
+ /**
64
+ * Returns a list of operators to add to the existing list.
65
+ *
66
+ * @return array An array of operators
67
+ */
68
+ public function getOperators();
69
+
70
+ /**
71
+ * Returns a list of global variables to add to the existing list.
72
+ *
73
+ * @return array An array of global variables
74
+ */
75
+ public function getGlobals();
76
+
77
+ /**
78
+ * Returns the name of the extension.
79
+ *
80
+ * @return string The extension name
81
+ */
82
+ public function getName();
83
+ }
vendor/vendor/twig/twig/lib/Twig/Filter.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
21
+ {
22
+ protected $options;
23
+ protected $arguments = array();
24
+
25
+ public function __construct(array $options = array())
26
+ {
27
+ $this->options = array_merge(array(
28
+ 'needs_environment' => false,
29
+ 'needs_context' => false,
30
+ 'pre_escape' => null,
31
+ 'preserves_safety' => null,
32
+ 'callable' => null,
33
+ ), $options);
34
+ }
35
+
36
+ public function setArguments($arguments)
37
+ {
38
+ $this->arguments = $arguments;
39
+ }
40
+
41
+ public function getArguments()
42
+ {
43
+ return $this->arguments;
44
+ }
45
+
46
+ public function needsEnvironment()
47
+ {
48
+ return $this->options['needs_environment'];
49
+ }
50
+
51
+ public function needsContext()
52
+ {
53
+ return $this->options['needs_context'];
54
+ }
55
+
56
+ public function getSafe(Twig_Node $filterArgs)
57
+ {
58
+ if (isset($this->options['is_safe'])) {
59
+ return $this->options['is_safe'];
60
+ }
61
+
62
+ if (isset($this->options['is_safe_callback'])) {
63
+ return call_user_func($this->options['is_safe_callback'], $filterArgs);
64
+ }
65
+ }
66
+
67
+ public function getPreservesSafety()
68
+ {
69
+ return $this->options['preserves_safety'];
70
+ }
71
+
72
+ public function getPreEscape()
73
+ {
74
+ return $this->options['pre_escape'];
75
+ }
76
+
77
+ public function getCallable()
78
+ {
79
+ return $this->options['callable'];
80
+ }
81
+ }
vendor/vendor/twig/twig/lib/Twig/Filter/Function.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a function template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Filter_Function extends Twig_Filter
21
+ {
22
+ protected $function;
23
+
24
+ public function __construct($function, array $options = array())
25
+ {
26
+ $options['callable'] = $function;
27
+
28
+ parent::__construct($options);
29
+
30
+ $this->function = $function;
31
+ }
32
+
33
+ public function compile()
34
+ {
35
+ return $this->function;
36
+ }
37
+ }
vendor/vendor/twig/twig/lib/Twig/Filter/Method.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a method template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Filter_Method extends Twig_Filter
21
+ {
22
+ protected $extension;
23
+ protected $method;
24
+
25
+ public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
26
+ {
27
+ $options['callable'] = array($extension, $method);
28
+
29
+ parent::__construct($options);
30
+
31
+ $this->extension = $extension;
32
+ $this->method = $method;
33
+ }
34
+
35
+ public function compile()
36
+ {
37
+ return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
38
+ }
39
+ }
vendor/vendor/twig/twig/lib/Twig/Filter/Node.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter as a node.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Filter_Node extends Twig_Filter
21
+ {
22
+ protected $class;
23
+
24
+ public function __construct($class, array $options = array())
25
+ {
26
+ parent::__construct($options);
27
+
28
+ $this->class = $class;
29
+ }
30
+
31
+ public function getClass()
32
+ {
33
+ return $this->class;
34
+ }
35
+
36
+ public function compile()
37
+ {
38
+ }
39
+ }
vendor/vendor/twig/twig/lib/Twig/FilterCallableInterface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a callable template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ interface Twig_FilterCallableInterface
21
+ {
22
+ public function getCallable();
23
+ }
vendor/vendor/twig/twig/lib/Twig/FilterInterface.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template filter.
14
+ *
15
+ * Use Twig_SimpleFilter instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ interface Twig_FilterInterface
21
+ {
22
+ /**
23
+ * Compiles a filter.
24
+ *
25
+ * @return string The PHP code for the filter
26
+ */
27
+ public function compile();
28
+
29
+ public function needsEnvironment();
30
+
31
+ public function needsContext();
32
+
33
+ public function getSafe(Twig_Node $filterArgs);
34
+
35
+ public function getPreservesSafety();
36
+
37
+ public function getPreEscape();
38
+
39
+ public function setArguments($arguments);
40
+
41
+ public function getArguments();
42
+ }
vendor/vendor/twig/twig/lib/Twig/Function.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template function.
14
+ *
15
+ * Use Twig_SimpleFunction instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
21
+ {
22
+ protected $options;
23
+ protected $arguments = array();
24
+
25
+ public function __construct(array $options = array())
26
+ {
27
+ $this->options = array_merge(array(
28
+ 'needs_environment' => false,
29
+ 'needs_context' => false,
30
+ 'callable' => null,
31
+ ), $options);
32
+ }
33
+
34
+ public function setArguments($arguments)
35
+ {
36
+ $this->arguments = $arguments;
37
+ }
38
+
39
+ public function getArguments()
40
+ {
41
+ return $this->arguments;
42
+ }
43
+
44
+ public function needsEnvironment()
45
+ {
46
+ return $this->options['needs_environment'];
47
+ }
48
+
49
+ public function needsContext()
50
+ {
51
+ return $this->options['needs_context'];
52
+ }
53
+
54
+ public function getSafe(Twig_Node $functionArgs)
55
+ {
56
+ if (isset($this->options['is_safe'])) {
57
+ return $this->options['is_safe'];
58
+ }
59
+
60
+ if (isset($this->options['is_safe_callback'])) {
61
+ return call_user_func($this->options['is_safe_callback'], $functionArgs);
62
+ }
63
+
64
+ return array();
65
+ }
66
+
67
+ public function getCallable()
68
+ {
69
+ return $this->options['callable'];
70
+ }
71
+ }
vendor/vendor/twig/twig/lib/Twig/Function/Function.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a function template function.
15
+ *
16
+ * Use Twig_SimpleFunction instead.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ class Twig_Function_Function extends Twig_Function
22
+ {
23
+ protected $function;
24
+
25
+ public function __construct($function, array $options = array())
26
+ {
27
+ $options['callable'] = $function;
28
+
29
+ parent::__construct($options);
30
+
31
+ $this->function = $function;
32
+ }
33
+
34
+ public function compile()
35
+ {
36
+ return $this->function;
37
+ }
38
+ }
vendor/vendor/twig/twig/lib/Twig/Function/Method.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a method template function.
15
+ *
16
+ * Use Twig_SimpleFunction instead.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ class Twig_Function_Method extends Twig_Function
22
+ {
23
+ protected $extension;
24
+ protected $method;
25
+
26
+ public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
27
+ {
28
+ $options['callable'] = array($extension, $method);
29
+
30
+ parent::__construct($options);
31
+
32
+ $this->extension = $extension;
33
+ $this->method = $method;
34
+ }
35
+
36
+ public function compile()
37
+ {
38
+ return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
39
+ }
40
+ }
vendor/vendor/twig/twig/lib/Twig/Function/Node.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a template function as a node.
14
+ *
15
+ * Use Twig_SimpleFunction instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ class Twig_Function_Node extends Twig_Function
21
+ {
22
+ protected $class;
23
+
24
+ public function __construct($class, array $options = array())
25
+ {
26
+ parent::__construct($options);
27
+
28
+ $this->class = $class;
29
+ }
30
+
31
+ public function getClass()
32
+ {
33
+ return $this->class;
34
+ }
35
+
36
+ public function compile()
37
+ {
38
+ }
39
+ }
vendor/vendor/twig/twig/lib/Twig/FunctionCallableInterface.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a callable template function.
14
+ *
15
+ * Use Twig_SimpleFunction instead.
16
+ *
17
+ * @author Fabien Potencier <fabien@symfony.com>
18
+ * @deprecated since 1.12 (to be removed in 2.0)
19
+ */
20
+ interface Twig_FunctionCallableInterface
21
+ {
22
+ public function getCallable();
23
+ }
vendor/vendor/twig/twig/lib/Twig/FunctionInterface.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ * (c) 2010 Arnaud Le Blanc
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a template function.
15
+ *
16
+ * Use Twig_SimpleFunction instead.
17
+ *
18
+ * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
19
+ * @deprecated since 1.12 (to be removed in 2.0)
20
+ */
21
+ interface Twig_FunctionInterface
22
+ {
23
+ /**
24
+ * Compiles a function.
25
+ *
26
+ * @return string The PHP code for the function
27
+ */
28
+ public function compile();
29
+
30
+ public function needsEnvironment();
31
+
32
+ public function needsContext();
33
+
34
+ public function getSafe(Twig_Node $filterArgs);
35
+
36
+ public function setArguments($arguments);
37
+
38
+ public function getArguments();
39
+ }
vendor/vendor/twig/twig/lib/Twig/Lexer.php ADDED
@@ -0,0 +1,409 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Lexes a template string.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Lexer implements Twig_LexerInterface
19
+ {
20
+ protected $tokens;
21
+ protected $code;
22
+ protected $cursor;
23
+ protected $lineno;
24
+ protected $end;
25
+ protected $state;
26
+ protected $states;
27
+ protected $brackets;
28
+ protected $env;
29
+ protected $filename;
30
+ protected $options;
31
+ protected $regexes;
32
+ protected $position;
33
+ protected $positions;
34
+ protected $currentVarBlockLine;
35
+
36
+ const STATE_DATA = 0;
37
+ const STATE_BLOCK = 1;
38
+ const STATE_VAR = 2;
39
+ const STATE_STRING = 3;
40
+ const STATE_INTERPOLATION = 4;
41
+
42
+ const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
43
+ const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
44
+ const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
45
+ const REGEX_DQ_STRING_DELIM = '/"/A';
46
+ const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
47
+ const PUNCTUATION = '()[]{}?:.,|';
48
+
49
+ public function __construct(Twig_Environment $env, array $options = array())
50
+ {
51
+ $this->env = $env;
52
+
53
+ $this->options = array_merge(array(
54
+ 'tag_comment' => array('{#', '#}'),
55
+ 'tag_block' => array('{%', '%}'),
56
+ 'tag_variable' => array('{{', '}}'),
57
+ 'whitespace_trim' => '-',
58
+ 'interpolation' => array('#{', '}'),
59
+ ), $options);
60
+
61
+ $this->regexes = array(
62
+ 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
63
+ 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
64
+ 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
65
+ 'operator' => $this->getOperatorRegex(),
66
+ 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
67
+ 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
68
+ 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
69
+ 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
70
+ 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
71
+ 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
72
+ );
73
+ }
74
+
75
+ /**
76
+ * {@inheritdoc}
77
+ */
78
+ public function tokenize($code, $filename = null)
79
+ {
80
+ if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
81
+ $mbEncoding = mb_internal_encoding();
82
+ mb_internal_encoding('ASCII');
83
+ } else {
84
+ $mbEncoding = null;
85
+ }
86
+
87
+ $this->code = str_replace(array("\r\n", "\r"), "\n", $code);
88
+ $this->filename = $filename;
89
+ $this->cursor = 0;
90
+ $this->lineno = 1;
91
+ $this->end = strlen($this->code);
92
+ $this->tokens = array();
93
+ $this->state = self::STATE_DATA;
94
+ $this->states = array();
95
+ $this->brackets = array();
96
+ $this->position = -1;
97
+
98
+ // find all token starts in one go
99
+ preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
100
+ $this->positions = $matches;
101
+
102
+ while ($this->cursor < $this->end) {
103
+ // dispatch to the lexing functions depending
104
+ // on the current state
105
+ switch ($this->state) {
106
+ case self::STATE_DATA:
107
+ $this->lexData();
108
+ break;
109
+
110
+ case self::STATE_BLOCK:
111
+ $this->lexBlock();
112
+ break;
113
+
114
+ case self::STATE_VAR:
115
+ $this->lexVar();
116
+ break;
117
+
118
+ case self::STATE_STRING:
119
+ $this->lexString();
120
+ break;
121
+
122
+ case self::STATE_INTERPOLATION:
123
+ $this->lexInterpolation();
124
+ break;
125
+ }
126
+ }
127
+
128
+ $this->pushToken(Twig_Token::EOF_TYPE);
129
+
130
+ if (!empty($this->brackets)) {
131
+ list($expect, $lineno) = array_pop($this->brackets);
132
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
133
+ }
134
+
135
+ if ($mbEncoding) {
136
+ mb_internal_encoding($mbEncoding);
137
+ }
138
+
139
+ return new Twig_TokenStream($this->tokens, $this->filename);
140
+ }
141
+
142
+ protected function lexData()
143
+ {
144
+ // if no matches are left we return the rest of the template as simple text token
145
+ if ($this->position == count($this->positions[0]) - 1) {
146
+ $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
147
+ $this->cursor = $this->end;
148
+
149
+ return;
150
+ }
151
+
152
+ // Find the first token after the current cursor
153
+ $position = $this->positions[0][++$this->position];
154
+ while ($position[1] < $this->cursor) {
155
+ if ($this->position == count($this->positions[0]) - 1) {
156
+ return;
157
+ }
158
+ $position = $this->positions[0][++$this->position];
159
+ }
160
+
161
+ // push the template text first
162
+ $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
163
+ if (isset($this->positions[2][$this->position][0])) {
164
+ $text = rtrim($text);
165
+ }
166
+ $this->pushToken(Twig_Token::TEXT_TYPE, $text);
167
+ $this->moveCursor($textContent.$position[0]);
168
+
169
+ switch ($this->positions[1][$this->position][0]) {
170
+ case $this->options['tag_comment'][0]:
171
+ $this->lexComment();
172
+ break;
173
+
174
+ case $this->options['tag_block'][0]:
175
+ // raw data?
176
+ if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
177
+ $this->moveCursor($match[0]);
178
+ $this->lexRawData($match[1]);
179
+ // {% line \d+ %}
180
+ } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
181
+ $this->moveCursor($match[0]);
182
+ $this->lineno = (int) $match[1];
183
+ } else {
184
+ $this->pushToken(Twig_Token::BLOCK_START_TYPE);
185
+ $this->pushState(self::STATE_BLOCK);
186
+ $this->currentVarBlockLine = $this->lineno;
187
+ }
188
+ break;
189
+
190
+ case $this->options['tag_variable'][0]:
191
+ $this->pushToken(Twig_Token::VAR_START_TYPE);
192
+ $this->pushState(self::STATE_VAR);
193
+ $this->currentVarBlockLine = $this->lineno;
194
+ break;
195
+ }
196
+ }
197
+
198
+ protected function lexBlock()
199
+ {
200
+ if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
201
+ $this->pushToken(Twig_Token::BLOCK_END_TYPE);
202
+ $this->moveCursor($match[0]);
203
+ $this->popState();
204
+ } else {
205
+ $this->lexExpression();
206
+ }
207
+ }
208
+
209
+ protected function lexVar()
210
+ {
211
+ if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
212
+ $this->pushToken(Twig_Token::VAR_END_TYPE);
213
+ $this->moveCursor($match[0]);
214
+ $this->popState();
215
+ } else {
216
+ $this->lexExpression();
217
+ }
218
+ }
219
+
220
+ protected function lexExpression()
221
+ {
222
+ // whitespace
223
+ if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
224
+ $this->moveCursor($match[0]);
225
+
226
+ if ($this->cursor >= $this->end) {
227
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
228
+ }
229
+ }
230
+
231
+ // operators
232
+ if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
233
+ $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0]));
234
+ $this->moveCursor($match[0]);
235
+ }
236
+ // names
237
+ elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
238
+ $this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
239
+ $this->moveCursor($match[0]);
240
+ }
241
+ // numbers
242
+ elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
243
+ $number = (float) $match[0]; // floats
244
+ if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
245
+ $number = (int) $match[0]; // integers lower than the maximum
246
+ }
247
+ $this->pushToken(Twig_Token::NUMBER_TYPE, $number);
248
+ $this->moveCursor($match[0]);
249
+ }
250
+ // punctuation
251
+ elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
252
+ // opening bracket
253
+ if (false !== strpos('([{', $this->code[$this->cursor])) {
254
+ $this->brackets[] = array($this->code[$this->cursor], $this->lineno);
255
+ }
256
+ // closing bracket
257
+ elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
258
+ if (empty($this->brackets)) {
259
+ throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
260
+ }
261
+
262
+ list($expect, $lineno) = array_pop($this->brackets);
263
+ if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
264
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
265
+ }
266
+ }
267
+
268
+ $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
269
+ ++$this->cursor;
270
+ }
271
+ // strings
272
+ elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
273
+ $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
274
+ $this->moveCursor($match[0]);
275
+ }
276
+ // opening double quoted string
277
+ elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
278
+ $this->brackets[] = array('"', $this->lineno);
279
+ $this->pushState(self::STATE_STRING);
280
+ $this->moveCursor($match[0]);
281
+ }
282
+ // unlexable
283
+ else {
284
+ throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
285
+ }
286
+ }
287
+
288
+ protected function lexRawData($tag)
289
+ {
290
+ if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
291
+ throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
292
+ }
293
+
294
+ $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
295
+ $this->moveCursor($text.$match[0][0]);
296
+
297
+ if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
298
+ $text = rtrim($text);
299
+ }
300
+
301
+ $this->pushToken(Twig_Token::TEXT_TYPE, $text);
302
+ }
303
+
304
+ protected function lexComment()
305
+ {
306
+ if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
307
+ throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
308
+ }
309
+
310
+ $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
311
+ }
312
+
313
+ protected function lexString()
314
+ {
315
+ if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
316
+ $this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
317
+ $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
318
+ $this->moveCursor($match[0]);
319
+ $this->pushState(self::STATE_INTERPOLATION);
320
+
321
+ } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
322
+ $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
323
+ $this->moveCursor($match[0]);
324
+
325
+ } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
326
+ list($expect, $lineno) = array_pop($this->brackets);
327
+ if ($this->code[$this->cursor] != '"') {
328
+ throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
329
+ }
330
+
331
+ $this->popState();
332
+ ++$this->cursor;
333
+ }
334
+ }
335
+
336
+ protected function lexInterpolation()
337
+ {
338
+ $bracket = end($this->brackets);
339
+ if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
340
+ array_pop($this->brackets);
341
+ $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
342
+ $this->moveCursor($match[0]);
343
+ $this->popState();
344
+ } else {
345
+ $this->lexExpression();
346
+ }
347
+ }
348
+
349
+ protected function pushToken($type, $value = '')
350
+ {
351
+ // do not push empty text tokens
352
+ if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
353
+ return;
354
+ }
355
+
356
+ $this->tokens[] = new Twig_Token($type, $value, $this->lineno);
357
+ }
358
+
359
+ protected function moveCursor($text)
360
+ {
361
+ $this->cursor += strlen($text);
362
+ $this->lineno += substr_count($text, "\n");
363
+ }
364
+
365
+ protected function getOperatorRegex()
366
+ {
367
+ $operators = array_merge(
368
+ array('='),
369
+ array_keys($this->env->getUnaryOperators()),
370
+ array_keys($this->env->getBinaryOperators())
371
+ );
372
+
373
+ $operators = array_combine($operators, array_map('strlen', $operators));
374
+ arsort($operators);
375
+
376
+ $regex = array();
377
+ foreach ($operators as $operator => $length) {
378
+ // an operator that ends with a character must be followed by
379
+ // a whitespace or a parenthesis
380
+ if (ctype_alpha($operator[$length - 1])) {
381
+ $r = preg_quote($operator, '/').'(?=[\s()])';
382
+ } else {
383
+ $r = preg_quote($operator, '/');
384
+ }
385
+
386
+ // an operator with a space can be any amount of whitespaces
387
+ $r = preg_replace('/\s+/', '\s+', $r);
388
+
389
+ $regex[] = $r;
390
+ }
391
+
392
+ return '/'.implode('|', $regex).'/A';
393
+ }
394
+
395
+ protected function pushState($state)
396
+ {
397
+ $this->states[] = $this->state;
398
+ $this->state = $state;
399
+ }
400
+
401
+ protected function popState()
402
+ {
403
+ if (0 === count($this->states)) {
404
+ throw new Exception('Cannot pop state without a previous state');
405
+ }
406
+
407
+ $this->state = array_pop($this->states);
408
+ }
409
+ }
vendor/vendor/twig/twig/lib/Twig/LexerInterface.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface implemented by lexer classes.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ * @deprecated since 1.12 (to be removed in 2.0)
17
+ */
18
+ interface Twig_LexerInterface
19
+ {
20
+ /**
21
+ * Tokenizes a source code.
22
+ *
23
+ * @param string $code The source code
24
+ * @param string $filename A unique identifier for the source code
25
+ *
26
+ * @return Twig_TokenStream A token stream instance
27
+ *
28
+ * @throws Twig_Error_Syntax When the code is syntactically wrong
29
+ */
30
+ public function tokenize($code, $filename = null);
31
+ }
vendor/vendor/twig/twig/lib/Twig/Loader/Array.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads a template from an array.
14
+ *
15
+ * When using this loader with a cache mechanism, you should know that a new cache
16
+ * key is generated each time a template content "changes" (the cache key being the
17
+ * source code of the template). If you don't want to see your cache grows out of
18
+ * control, you need to take care of clearing the old cache file by yourself.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
23
+ {
24
+ protected $templates = array();
25
+
26
+ /**
27
+ * Constructor.
28
+ *
29
+ * @param array $templates An array of templates (keys are the names, and values are the source code)
30
+ *
31
+ * @see Twig_Loader
32
+ */
33
+ public function __construct(array $templates)
34
+ {
35
+ $this->templates = $templates;
36
+ }
37
+
38
+ /**
39
+ * Adds or overrides a template.
40
+ *
41
+ * @param string $name The template name
42
+ * @param string $template The template source
43
+ */
44
+ public function setTemplate($name, $template)
45
+ {
46
+ $this->templates[(string) $name] = $template;
47
+ }
48
+
49
+ /**
50
+ * {@inheritdoc}
51
+ */
52
+ public function getSource($name)
53
+ {
54
+ $name = (string) $name;
55
+ if (!isset($this->templates[$name])) {
56
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
57
+ }
58
+
59
+ return $this->templates[$name];
60
+ }
61
+
62
+ /**
63
+ * {@inheritdoc}
64
+ */
65
+ public function exists($name)
66
+ {
67
+ return isset($this->templates[(string) $name]);
68
+ }
69
+
70
+ /**
71
+ * {@inheritdoc}
72
+ */
73
+ public function getCacheKey($name)
74
+ {
75
+ $name = (string) $name;
76
+ if (!isset($this->templates[$name])) {
77
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
78
+ }
79
+
80
+ return $this->templates[$name];
81
+ }
82
+
83
+ /**
84
+ * {@inheritdoc}
85
+ */
86
+ public function isFresh($name, $time)
87
+ {
88
+ $name = (string) $name;
89
+ if (!isset($this->templates[$name])) {
90
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
91
+ }
92
+
93
+ return true;
94
+ }
95
+ }
vendor/vendor/twig/twig/lib/Twig/Loader/Chain.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads templates from other loaders.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18
+ {
19
+ private $hasSourceCache = array();
20
+ protected $loaders = array();
21
+
22
+ /**
23
+ * Constructor.
24
+ *
25
+ * @param Twig_LoaderInterface[] $loaders An array of loader instances
26
+ */
27
+ public function __construct(array $loaders = array())
28
+ {
29
+ foreach ($loaders as $loader) {
30
+ $this->addLoader($loader);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Adds a loader instance.
36
+ *
37
+ * @param Twig_LoaderInterface $loader A Loader instance
38
+ */
39
+ public function addLoader(Twig_LoaderInterface $loader)
40
+ {
41
+ $this->loaders[] = $loader;
42
+ $this->hasSourceCache = array();
43
+ }
44
+
45
+ /**
46
+ * {@inheritdoc}
47
+ */
48
+ public function getSource($name)
49
+ {
50
+ $exceptions = array();
51
+ foreach ($this->loaders as $loader) {
52
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
53
+ continue;
54
+ }
55
+
56
+ try {
57
+ return $loader->getSource($name);
58
+ } catch (Twig_Error_Loader $e) {
59
+ $exceptions[] = $e->getMessage();
60
+ }
61
+ }
62
+
63
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
64
+ }
65
+
66
+ /**
67
+ * {@inheritdoc}
68
+ */
69
+ public function exists($name)
70
+ {
71
+ $name = (string) $name;
72
+
73
+ if (isset($this->hasSourceCache[$name])) {
74
+ return $this->hasSourceCache[$name];
75
+ }
76
+
77
+ foreach ($this->loaders as $loader) {
78
+ if ($loader instanceof Twig_ExistsLoaderInterface) {
79
+ if ($loader->exists($name)) {
80
+ return $this->hasSourceCache[$name] = true;
81
+ }
82
+
83
+ continue;
84
+ }
85
+
86
+ try {
87
+ $loader->getSource($name);
88
+
89
+ return $this->hasSourceCache[$name] = true;
90
+ } catch (Twig_Error_Loader $e) {
91
+ }
92
+ }
93
+
94
+ return $this->hasSourceCache[$name] = false;
95
+ }
96
+
97
+ /**
98
+ * {@inheritdoc}
99
+ */
100
+ public function getCacheKey($name)
101
+ {
102
+ $exceptions = array();
103
+ foreach ($this->loaders as $loader) {
104
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
105
+ continue;
106
+ }
107
+
108
+ try {
109
+ return $loader->getCacheKey($name);
110
+ } catch (Twig_Error_Loader $e) {
111
+ $exceptions[] = get_class($loader).': '.$e->getMessage();
112
+ }
113
+ }
114
+
115
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
116
+ }
117
+
118
+ /**
119
+ * {@inheritdoc}
120
+ */
121
+ public function isFresh($name, $time)
122
+ {
123
+ $exceptions = array();
124
+ foreach ($this->loaders as $loader) {
125
+ if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
126
+ continue;
127
+ }
128
+
129
+ try {
130
+ return $loader->isFresh($name, $time);
131
+ } catch (Twig_Error_Loader $e) {
132
+ $exceptions[] = get_class($loader).': '.$e->getMessage();
133
+ }
134
+ }
135
+
136
+ throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
137
+ }
138
+ }
vendor/vendor/twig/twig/lib/Twig/Loader/Filesystem.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads template from the filesystem.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
18
+ {
19
+ /** Identifier of the main namespace. */
20
+ const MAIN_NAMESPACE = '__main__';
21
+
22
+ protected $paths = array();
23
+ protected $cache = array();
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * @param string|array $paths A path or an array of paths where to look for templates
29
+ */
30
+ public function __construct($paths = array())
31
+ {
32
+ if ($paths) {
33
+ $this->setPaths($paths);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Returns the paths to the templates.
39
+ *
40
+ * @param string $namespace A path namespace
41
+ *
42
+ * @return array The array of paths where to look for templates
43
+ */
44
+ public function getPaths($namespace = self::MAIN_NAMESPACE)
45
+ {
46
+ return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
47
+ }
48
+
49
+ /**
50
+ * Returns the path namespaces.
51
+ *
52
+ * The main namespace is always defined.
53
+ *
54
+ * @return array The array of defined namespaces
55
+ */
56
+ public function getNamespaces()
57
+ {
58
+ return array_keys($this->paths);
59
+ }
60
+
61
+ /**
62
+ * Sets the paths where templates are stored.
63
+ *
64
+ * @param string|array $paths A path or an array of paths where to look for templates
65
+ * @param string $namespace A path namespace
66
+ */
67
+ public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
68
+ {
69
+ if (!is_array($paths)) {
70
+ $paths = array($paths);
71
+ }
72
+
73
+ $this->paths[$namespace] = array();
74
+ foreach ($paths as $path) {
75
+ $this->addPath($path, $namespace);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Adds a path where templates are stored.
81
+ *
82
+ * @param string $path A path where to look for templates
83
+ * @param string $namespace A path name
84
+ *
85
+ * @throws Twig_Error_Loader
86
+ */
87
+ public function addPath($path, $namespace = self::MAIN_NAMESPACE)
88
+ {
89
+ // invalidate the cache
90
+ $this->cache = array();
91
+
92
+ if (!is_dir($path)) {
93
+ throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
94
+ }
95
+
96
+ $this->paths[$namespace][] = rtrim($path, '/\\');
97
+ }
98
+
99
+ /**
100
+ * Prepends a path where templates are stored.
101
+ *
102
+ * @param string $path A path where to look for templates
103
+ * @param string $namespace A path name
104
+ *
105
+ * @throws Twig_Error_Loader
106
+ */
107
+ public function prependPath($path, $namespace = self::MAIN_NAMESPACE)
108
+ {
109
+ // invalidate the cache
110
+ $this->cache = array();
111
+
112
+ if (!is_dir($path)) {
113
+ throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
114
+ }
115
+
116
+ $path = rtrim($path, '/\\');
117
+
118
+ if (!isset($this->paths[$namespace])) {
119
+ $this->paths[$namespace][] = $path;
120
+ } else {
121
+ array_unshift($this->paths[$namespace], $path);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * {@inheritdoc}
127
+ */
128
+ public function getSource($name)
129
+ {
130
+ return file_get_contents($this->findTemplate($name));
131
+ }
132
+
133
+ /**
134
+ * {@inheritdoc}
135
+ */
136
+ public function getCacheKey($name)
137
+ {
138
+ return $this->findTemplate($name);
139
+ }
140
+
141
+ /**
142
+ * {@inheritdoc}
143
+ */
144
+ public function exists($name)
145
+ {
146
+ $name = $this->normalizeName($name);
147
+
148
+ if (isset($this->cache[$name])) {
149
+ return true;
150
+ }
151
+
152
+ try {
153
+ $this->findTemplate($name);
154
+
155
+ return true;
156
+ } catch (Twig_Error_Loader $exception) {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * {@inheritdoc}
163
+ */
164
+ public function isFresh($name, $time)
165
+ {
166
+ return filemtime($this->findTemplate($name)) <= $time;
167
+ }
168
+
169
+ protected function findTemplate($name)
170
+ {
171
+ $name = $this->normalizeName($name);
172
+
173
+ if (isset($this->cache[$name])) {
174
+ return $this->cache[$name];
175
+ }
176
+
177
+ $this->validateName($name);
178
+
179
+ $namespace = self::MAIN_NAMESPACE;
180
+ $shortname = $name;
181
+ if (isset($name[0]) && '@' == $name[0]) {
182
+ if (false === $pos = strpos($name, '/')) {
183
+ throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
184
+ }
185
+
186
+ $namespace = substr($name, 1, $pos - 1);
187
+ $shortname = substr($name, $pos + 1);
188
+ }
189
+
190
+ if (!isset($this->paths[$namespace])) {
191
+ throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
192
+ }
193
+
194
+ foreach ($this->paths[$namespace] as $path) {
195
+ if (is_file($path.'/'.$shortname)) {
196
+ return $this->cache[$name] = $path.'/'.$shortname;
197
+ }
198
+ }
199
+
200
+ throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
201
+ }
202
+
203
+ protected function normalizeName($name)
204
+ {
205
+ return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));
206
+ }
207
+
208
+ protected function validateName($name)
209
+ {
210
+ if (false !== strpos($name, "\0")) {
211
+ throw new Twig_Error_Loader('A template name cannot contain NUL bytes.');
212
+ }
213
+
214
+ $name = ltrim($name, '/');
215
+ $parts = explode('/', $name);
216
+ $level = 0;
217
+ foreach ($parts as $part) {
218
+ if ('..' === $part) {
219
+ --$level;
220
+ } elseif ('.' !== $part) {
221
+ ++$level;
222
+ }
223
+
224
+ if ($level < 0) {
225
+ throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
226
+ }
227
+ }
228
+ }
229
+ }
vendor/vendor/twig/twig/lib/Twig/Loader/String.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Loads a template from a string.
14
+ *
15
+ * This loader should only be used for unit testing as it has many limitations
16
+ * (for instance, the include or extends tag does not make any sense for a string
17
+ * loader).
18
+ *
19
+ * When using this loader with a cache mechanism, you should know that a new cache
20
+ * key is generated each time a template content "changes" (the cache key being the
21
+ * source code of the template). If you don't want to see your cache grows out of
22
+ * control, you need to take care of clearing the old cache file by yourself.
23
+ *
24
+ * @author Fabien Potencier <fabien@symfony.com>
25
+ */
26
+ class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
27
+ {
28
+ /**
29
+ * {@inheritdoc}
30
+ */
31
+ public function getSource($name)
32
+ {
33
+ return $name;
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ */
39
+ public function exists($name)
40
+ {
41
+ return true;
42
+ }
43
+
44
+ /**
45
+ * {@inheritdoc}
46
+ */
47
+ public function getCacheKey($name)
48
+ {
49
+ return $name;
50
+ }
51
+
52
+ /**
53
+ * {@inheritdoc}
54
+ */
55
+ public function isFresh($name, $time)
56
+ {
57
+ return true;
58
+ }
59
+ }
vendor/vendor/twig/twig/lib/Twig/LoaderInterface.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Interface all loaders must implement.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ interface Twig_LoaderInterface
18
+ {
19
+ /**
20
+ * Gets the source code of a template, given its name.
21
+ *
22
+ * @param string $name The name of the template to load
23
+ *
24
+ * @return string The template source code
25
+ *
26
+ * @throws Twig_Error_Loader When $name is not found
27
+ */
28
+ public function getSource($name);
29
+
30
+ /**
31
+ * Gets the cache key to use for the cache for a given template name.
32
+ *
33
+ * @param string $name The name of the template to load
34
+ *
35
+ * @return string The cache key
36
+ *
37
+ * @throws Twig_Error_Loader When $name is not found
38
+ */
39
+ public function getCacheKey($name);
40
+
41
+ /**
42
+ * Returns true if the template is still fresh.
43
+ *
44
+ * @param string $name The template name
45
+ * @param timestamp $time The last modification time of the cached template
46
+ *
47
+ * @return Boolean true if the template is fresh, false otherwise
48
+ *
49
+ * @throws Twig_Error_Loader When $name is not found
50
+ */
51
+ public function isFresh($name, $time);
52
+ }
vendor/vendor/twig/twig/lib/Twig/Markup.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Marks a content as safe.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Markup implements Countable
18
+ {
19
+ protected $content;
20
+ protected $charset;
21
+
22
+ public function __construct($content, $charset)
23
+ {
24
+ $this->content = (string) $content;
25
+ $this->charset = $charset;
26
+ }
27
+
28
+ public function __toString()
29
+ {
30
+ return $this->content;
31
+ }
32
+
33
+ public function count()
34
+ {
35
+ return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content);
36
+ }
37
+ }
vendor/vendor/twig/twig/lib/Twig/Node.php ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a node in the AST.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node implements Twig_NodeInterface
19
+ {
20
+ protected $nodes;
21
+ protected $attributes;
22
+ protected $lineno;
23
+ protected $tag;
24
+
25
+ /**
26
+ * Constructor.
27
+ *
28
+ * The nodes are automatically made available as properties ($this->node).
29
+ * The attributes are automatically made available as array items ($this['name']).
30
+ *
31
+ * @param array $nodes An array of named nodes
32
+ * @param array $attributes An array of attributes (should not be nodes)
33
+ * @param integer $lineno The line number
34
+ * @param string $tag The tag name associated with the Node
35
+ */
36
+ public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
37
+ {
38
+ $this->nodes = $nodes;
39
+ $this->attributes = $attributes;
40
+ $this->lineno = $lineno;
41
+ $this->tag = $tag;
42
+ }
43
+
44
+ public function __toString()
45
+ {
46
+ $attributes = array();
47
+ foreach ($this->attributes as $name => $value) {
48
+ $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true)));
49
+ }
50
+
51
+ $repr = array(get_class($this).'('.implode(', ', $attributes));
52
+
53
+ if (count($this->nodes)) {
54
+ foreach ($this->nodes as $name => $node) {
55
+ $len = strlen($name) + 4;
56
+ $noderepr = array();
57
+ foreach (explode("\n", (string) $node) as $line) {
58
+ $noderepr[] = str_repeat(' ', $len).$line;
59
+ }
60
+
61
+ $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr)));
62
+ }
63
+
64
+ $repr[] = ')';
65
+ } else {
66
+ $repr[0] .= ')';
67
+ }
68
+
69
+ return implode("\n", $repr);
70
+ }
71
+
72
+ public function toXml($asDom = false)
73
+ {
74
+ $dom = new DOMDocument('1.0', 'UTF-8');
75
+ $dom->formatOutput = true;
76
+ $dom->appendChild($xml = $dom->createElement('twig'));
77
+
78
+ $xml->appendChild($node = $dom->createElement('node'));
79
+ $node->setAttribute('class', get_class($this));
80
+
81
+ foreach ($this->attributes as $name => $value) {
82
+ $node->appendChild($attribute = $dom->createElement('attribute'));
83
+ $attribute->setAttribute('name', $name);
84
+ $attribute->appendChild($dom->createTextNode($value));
85
+ }
86
+
87
+ foreach ($this->nodes as $name => $n) {
88
+ if (null === $n) {
89
+ continue;
90
+ }
91
+
92
+ $child = $n->toXml(true)->getElementsByTagName('node')->item(0);
93
+ $child = $dom->importNode($child, true);
94
+ $child->setAttribute('name', $name);
95
+
96
+ $node->appendChild($child);
97
+ }
98
+
99
+ return $asDom ? $dom : $dom->saveXml();
100
+ }
101
+
102
+ public function compile(Twig_Compiler $compiler)
103
+ {
104
+ foreach ($this->nodes as $node) {
105
+ $node->compile($compiler);
106
+ }
107
+ }
108
+
109
+ public function getLine()
110
+ {
111
+ return $this->lineno;
112
+ }
113
+
114
+ public function getNodeTag()
115
+ {
116
+ return $this->tag;
117
+ }
118
+
119
+ /**
120
+ * Returns true if the attribute is defined.
121
+ *
122
+ * @param string The attribute name
123
+ *
124
+ * @return Boolean true if the attribute is defined, false otherwise
125
+ */
126
+ public function hasAttribute($name)
127
+ {
128
+ return array_key_exists($name, $this->attributes);
129
+ }
130
+
131
+ /**
132
+ * Gets an attribute.
133
+ *
134
+ * @param string The attribute name
135
+ *
136
+ * @return mixed The attribute value
137
+ */
138
+ public function getAttribute($name)
139
+ {
140
+ if (!array_key_exists($name, $this->attributes)) {
141
+ throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this)));
142
+ }
143
+
144
+ return $this->attributes[$name];
145
+ }
146
+
147
+ /**
148
+ * Sets an attribute.
149
+ *
150
+ * @param string The attribute name
151
+ * @param mixed The attribute value
152
+ */
153
+ public function setAttribute($name, $value)
154
+ {
155
+ $this->attributes[$name] = $value;
156
+ }
157
+
158
+ /**
159
+ * Removes an attribute.
160
+ *
161
+ * @param string The attribute name
162
+ */
163
+ public function removeAttribute($name)
164
+ {
165
+ unset($this->attributes[$name]);
166
+ }
167
+
168
+ /**
169
+ * Returns true if the node with the given identifier exists.
170
+ *
171
+ * @param string The node name
172
+ *
173
+ * @return Boolean true if the node with the given name exists, false otherwise
174
+ */
175
+ public function hasNode($name)
176
+ {
177
+ return array_key_exists($name, $this->nodes);
178
+ }
179
+
180
+ /**
181
+ * Gets a node by name.
182
+ *
183
+ * @param string The node name
184
+ *
185
+ * @return Twig_Node A Twig_Node instance
186
+ */
187
+ public function getNode($name)
188
+ {
189
+ if (!array_key_exists($name, $this->nodes)) {
190
+ throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this)));
191
+ }
192
+
193
+ return $this->nodes[$name];
194
+ }
195
+
196
+ /**
197
+ * Sets a node.
198
+ *
199
+ * @param string The node name
200
+ * @param Twig_Node A Twig_Node instance
201
+ */
202
+ public function setNode($name, $node = null)
203
+ {
204
+ $this->nodes[$name] = $node;
205
+ }
206
+
207
+ /**
208
+ * Removes a node by name.
209
+ *
210
+ * @param string The node name
211
+ */
212
+ public function removeNode($name)
213
+ {
214
+ unset($this->nodes[$name]);
215
+ }
216
+
217
+ public function count()
218
+ {
219
+ return count($this->nodes);
220
+ }
221
+
222
+ public function getIterator()
223
+ {
224
+ return new ArrayIterator($this->nodes);
225
+ }
226
+ }
vendor/vendor/twig/twig/lib/Twig/Node/AutoEscape.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an autoescape node.
14
+ *
15
+ * The value is the escaping strategy (can be html, js, ...)
16
+ *
17
+ * The true value is equivalent to html.
18
+ *
19
+ * If autoescaping is disabled, then the value is false.
20
+ *
21
+ * @author Fabien Potencier <fabien@symfony.com>
22
+ */
23
+ class Twig_Node_AutoEscape extends Twig_Node
24
+ {
25
+ public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape')
26
+ {
27
+ parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag);
28
+ }
29
+
30
+ /**
31
+ * Compiles the node to PHP.
32
+ *
33
+ * @param Twig_Compiler A Twig_Compiler instance
34
+ */
35
+ public function compile(Twig_Compiler $compiler)
36
+ {
37
+ $compiler->subcompile($this->getNode('body'));
38
+ }
39
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Block.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a block node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Block extends Twig_Node
19
+ {
20
+ public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n")
35
+ ->indent()
36
+ ;
37
+
38
+ $compiler
39
+ ->subcompile($this->getNode('body'))
40
+ ->outdent()
41
+ ->write("}\n\n")
42
+ ;
43
+ }
44
+ }
vendor/vendor/twig/twig/lib/Twig/Node/BlockReference.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a block call node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct($name, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array(), array('name' => $name), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name')))
35
+ ;
36
+ }
37
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Body.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a body node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Body extends Twig_Node
18
+ {
19
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Do.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a do node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Do extends Twig_Node
18
+ {
19
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write('')
34
+ ->subcompile($this->getNode('expr'))
35
+ ->raw(";\n")
36
+ ;
37
+ }
38
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Embed.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an embed node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Embed extends Twig_Node_Include
18
+ {
19
+ // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module)
20
+ public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag);
23
+
24
+ $this->setAttribute('filename', $filename);
25
+ $this->setAttribute('index', $index);
26
+ }
27
+
28
+ protected function addGetTemplate(Twig_Compiler $compiler)
29
+ {
30
+ $compiler
31
+ ->write("\$this->env->loadTemplate(")
32
+ ->string($this->getAttribute('filename'))
33
+ ->raw(', ')
34
+ ->string($this->getAttribute('index'))
35
+ ->raw(")")
36
+ ;
37
+ }
38
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Abstract class for all nodes that represents an expression.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ abstract class Twig_Node_Expression extends Twig_Node
19
+ {
20
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Array.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Array extends Twig_Node_Expression
12
+ {
13
+ protected $index;
14
+
15
+ public function __construct(array $elements, $lineno)
16
+ {
17
+ parent::__construct($elements, array(), $lineno);
18
+
19
+ $this->index = -1;
20
+ foreach ($this->getKeyValuePairs() as $pair) {
21
+ if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) {
22
+ $this->index = $pair['key']->getAttribute('value');
23
+ }
24
+ }
25
+ }
26
+
27
+ public function getKeyValuePairs()
28
+ {
29
+ $pairs = array();
30
+
31
+ foreach (array_chunk($this->nodes, 2) as $pair) {
32
+ $pairs[] = array(
33
+ 'key' => $pair[0],
34
+ 'value' => $pair[1],
35
+ );
36
+ }
37
+
38
+ return $pairs;
39
+ }
40
+
41
+ public function hasElement(Twig_Node_Expression $key)
42
+ {
43
+ foreach ($this->getKeyValuePairs() as $pair) {
44
+ // we compare the string representation of the keys
45
+ // to avoid comparing the line numbers which are not relevant here.
46
+ if ((string) $key == (string) $pair['key']) {
47
+ return true;
48
+ }
49
+ }
50
+
51
+ return false;
52
+ }
53
+
54
+ public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null)
55
+ {
56
+ if (null === $key) {
57
+ $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine());
58
+ }
59
+
60
+ array_push($this->nodes, $key, $value);
61
+ }
62
+
63
+ /**
64
+ * Compiles the node to PHP.
65
+ *
66
+ * @param Twig_Compiler A Twig_Compiler instance
67
+ */
68
+ public function compile(Twig_Compiler $compiler)
69
+ {
70
+ $compiler->raw('array(');
71
+ $first = true;
72
+ foreach ($this->getKeyValuePairs() as $pair) {
73
+ if (!$first) {
74
+ $compiler->raw(', ');
75
+ }
76
+ $first = false;
77
+
78
+ $compiler
79
+ ->subcompile($pair['key'])
80
+ ->raw(' => ')
81
+ ->subcompile($pair['value'])
82
+ ;
83
+ }
84
+ $compiler->raw(')');
85
+ }
86
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/AssignName.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
14
+ {
15
+ /**
16
+ * Compiles the node to PHP.
17
+ *
18
+ * @param Twig_Compiler A Twig_Compiler instance
19
+ */
20
+ public function compile(Twig_Compiler $compiler)
21
+ {
22
+ $compiler
23
+ ->raw('$context[')
24
+ ->string($this->getAttribute('name'))
25
+ ->raw(']')
26
+ ;
27
+ }
28
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
15
+ {
16
+ parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno);
17
+ }
18
+
19
+ /**
20
+ * Compiles the node to PHP.
21
+ *
22
+ * @param Twig_Compiler A Twig_Compiler instance
23
+ */
24
+ public function compile(Twig_Compiler $compiler)
25
+ {
26
+ $compiler
27
+ ->raw('(')
28
+ ->subcompile($this->getNode('left'))
29
+ ->raw(' ')
30
+ ;
31
+ $this->operator($compiler);
32
+ $compiler
33
+ ->raw(' ')
34
+ ->subcompile($this->getNode('right'))
35
+ ->raw(')')
36
+ ;
37
+ }
38
+
39
+ abstract public function operator(Twig_Compiler $compiler);
40
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Add.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('+');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/And.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('&&');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('&');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('|');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('^');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('.');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Div.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('/');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2013 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
12
+ {
13
+ public function compile(Twig_Compiler $compiler)
14
+ {
15
+ $compiler
16
+ ->raw('(0 === substr_compare(')
17
+ ->subcompile($this->getNode('left'))
18
+ ->raw(', ')
19
+ ->subcompile($this->getNode('right'))
20
+ ->raw(', -strlen(')
21
+ ->subcompile($this->getNode('right'))
22
+ ->raw(')))')
23
+ ;
24
+ }
25
+
26
+ public function operator(Twig_Compiler $compiler)
27
+ {
28
+ return $compiler->raw('');
29
+ }
30
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('==');
16
+ }
17
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler->raw('intval(floor(');
21
+ parent::compile($compiler);
22
+ $compiler->raw('))');
23
+ }
24
+
25
+ public function operator(Twig_Compiler $compiler)
26
+ {
27
+ return $compiler->raw('/');
28
+ }
29
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('>');
16
+ }
17
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('>=');
16
+ }
17
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/In.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('twig_in_filter(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('in');
32
+ }
33
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Less.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('<');
16
+ }
17
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('<=');
16
+ }
17
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2013 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary
12
+ {
13
+ public function compile(Twig_Compiler $compiler)
14
+ {
15
+ $compiler
16
+ ->raw('preg_match(')
17
+ ->subcompile($this->getNode('right'))
18
+ ->raw(', ')
19
+ ->subcompile($this->getNode('left'))
20
+ ->raw(')')
21
+ ;
22
+ }
23
+
24
+ public function operator(Twig_Compiler $compiler)
25
+ {
26
+ return $compiler->raw('');
27
+ }
28
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('%');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('*');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary
12
+ {
13
+ public function operator(Twig_Compiler $compiler)
14
+ {
15
+ return $compiler->raw('!=');
16
+ }
17
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('!twig_in_filter(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('not in');
32
+ }
33
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Or.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('||');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Power.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('pow(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('**');
32
+ }
33
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Range.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
12
+ {
13
+ /**
14
+ * Compiles the node to PHP.
15
+ *
16
+ * @param Twig_Compiler A Twig_Compiler instance
17
+ */
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('range(')
22
+ ->subcompile($this->getNode('left'))
23
+ ->raw(', ')
24
+ ->subcompile($this->getNode('right'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ public function operator(Twig_Compiler $compiler)
30
+ {
31
+ return $compiler->raw('..');
32
+ }
33
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2013 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
12
+ {
13
+ public function compile(Twig_Compiler $compiler)
14
+ {
15
+ $compiler
16
+ ->raw('(0 === strpos(')
17
+ ->subcompile($this->getNode('left'))
18
+ ->raw(', ')
19
+ ->subcompile($this->getNode('right'))
20
+ ->raw('))')
21
+ ;
22
+ }
23
+
24
+ public function operator(Twig_Compiler $compiler)
25
+ {
26
+ return $compiler->raw('');
27
+ }
28
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ return $compiler->raw('-');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/BlockReference.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a block call node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
19
+ {
20
+ public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ if ($this->getAttribute('as_string')) {
33
+ $compiler->raw('(string) ');
34
+ }
35
+
36
+ if ($this->getAttribute('output')) {
37
+ $compiler
38
+ ->addDebugInfo($this)
39
+ ->write("\$this->displayBlock(")
40
+ ->subcompile($this->getNode('name'))
41
+ ->raw(", \$context, \$blocks);\n")
42
+ ;
43
+ } else {
44
+ $compiler
45
+ ->raw("\$this->renderBlock(")
46
+ ->subcompile($this->getNode('name'))
47
+ ->raw(", \$context, \$blocks)")
48
+ ;
49
+ }
50
+ }
51
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Call.php ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
12
+ {
13
+ protected function compileCallable(Twig_Compiler $compiler)
14
+ {
15
+ $callable = $this->getAttribute('callable');
16
+
17
+ $closingParenthesis = false;
18
+ if ($callable) {
19
+ if (is_string($callable)) {
20
+ $compiler->raw($callable);
21
+ } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
22
+ $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
23
+ } else {
24
+ $type = ucfirst($this->getAttribute('type'));
25
+ $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
26
+ $closingParenthesis = true;
27
+ }
28
+ } else {
29
+ $compiler->raw($this->getAttribute('thing')->compile());
30
+ }
31
+
32
+ $this->compileArguments($compiler);
33
+
34
+ if ($closingParenthesis) {
35
+ $compiler->raw(')');
36
+ }
37
+ }
38
+
39
+ protected function compileArguments(Twig_Compiler $compiler)
40
+ {
41
+ $compiler->raw('(');
42
+
43
+ $first = true;
44
+
45
+ if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
46
+ $compiler->raw('$this->env');
47
+ $first = false;
48
+ }
49
+
50
+ if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
51
+ if (!$first) {
52
+ $compiler->raw(', ');
53
+ }
54
+ $compiler->raw('$context');
55
+ $first = false;
56
+ }
57
+
58
+ if ($this->hasAttribute('arguments')) {
59
+ foreach ($this->getAttribute('arguments') as $argument) {
60
+ if (!$first) {
61
+ $compiler->raw(', ');
62
+ }
63
+ $compiler->string($argument);
64
+ $first = false;
65
+ }
66
+ }
67
+
68
+ if ($this->hasNode('node')) {
69
+ if (!$first) {
70
+ $compiler->raw(', ');
71
+ }
72
+ $compiler->subcompile($this->getNode('node'));
73
+ $first = false;
74
+ }
75
+
76
+ if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
77
+ $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
78
+
79
+ $arguments = $this->getArguments($callable, $this->getNode('arguments'));
80
+
81
+ foreach ($arguments as $node) {
82
+ if (!$first) {
83
+ $compiler->raw(', ');
84
+ }
85
+ $compiler->subcompile($node);
86
+ $first = false;
87
+ }
88
+ }
89
+
90
+ $compiler->raw(')');
91
+ }
92
+
93
+ protected function getArguments($callable, $arguments)
94
+ {
95
+ $parameters = array();
96
+ $named = false;
97
+ foreach ($arguments as $name => $node) {
98
+ if (!is_int($name)) {
99
+ $named = true;
100
+ $name = $this->normalizeName($name);
101
+ } elseif ($named) {
102
+ throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
103
+ }
104
+
105
+ $parameters[$name] = $node;
106
+ }
107
+
108
+ if (!$named) {
109
+ return $parameters;
110
+ }
111
+
112
+ if (!$callable) {
113
+ throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
114
+ }
115
+
116
+ // manage named arguments
117
+ if (is_array($callable)) {
118
+ $r = new ReflectionMethod($callable[0], $callable[1]);
119
+ } elseif (is_object($callable) && !$callable instanceof Closure) {
120
+ $r = new ReflectionObject($callable);
121
+ $r = $r->getMethod('__invoke');
122
+ } else {
123
+ $r = new ReflectionFunction($callable);
124
+ }
125
+
126
+ $definition = $r->getParameters();
127
+ if ($this->hasNode('node')) {
128
+ array_shift($definition);
129
+ }
130
+ if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
131
+ array_shift($definition);
132
+ }
133
+ if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
134
+ array_shift($definition);
135
+ }
136
+ if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
137
+ foreach ($this->getAttribute('arguments') as $argument) {
138
+ array_shift($definition);
139
+ }
140
+ }
141
+
142
+ $arguments = array();
143
+ $pos = 0;
144
+ foreach ($definition as $param) {
145
+ $name = $this->normalizeName($param->name);
146
+
147
+ if (array_key_exists($name, $parameters)) {
148
+ if (array_key_exists($pos, $parameters)) {
149
+ throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
150
+ }
151
+
152
+ $arguments[] = $parameters[$name];
153
+ unset($parameters[$name]);
154
+ } elseif (array_key_exists($pos, $parameters)) {
155
+ $arguments[] = $parameters[$pos];
156
+ unset($parameters[$pos]);
157
+ ++$pos;
158
+ } elseif ($param->isDefaultValueAvailable()) {
159
+ $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
160
+ } elseif ($param->isOptional()) {
161
+ break;
162
+ } else {
163
+ throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
164
+ }
165
+ }
166
+
167
+ if (!empty($parameters)) {
168
+ throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
169
+ }
170
+
171
+ return $arguments;
172
+ }
173
+
174
+ protected function normalizeName($name)
175
+ {
176
+ return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
177
+ }
178
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Conditional.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Conditional extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_Node_Expression $expr1, Twig_Node_Expression $expr2, Twig_Node_Expression $expr3, $lineno)
15
+ {
16
+ parent::__construct(array('expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler
22
+ ->raw('((')
23
+ ->subcompile($this->getNode('expr1'))
24
+ ->raw(') ? (')
25
+ ->subcompile($this->getNode('expr2'))
26
+ ->raw(') : (')
27
+ ->subcompile($this->getNode('expr3'))
28
+ ->raw('))')
29
+ ;
30
+ }
31
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Constant.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Constant extends Twig_Node_Expression
13
+ {
14
+ public function __construct($value, $lineno)
15
+ {
16
+ parent::__construct(array(), array('value' => $value), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler->repr($this->getAttribute('value'));
22
+ }
23
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an extension call node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
18
+ {
19
+ public function __construct($name, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array(), array('name' => $name), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name')));
32
+ }
33
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Filter.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call
13
+ {
14
+ public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
15
+ {
16
+ parent::__construct(array('node' => $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $name = $this->getNode('filter')->getAttribute('value');
22
+ $filter = $compiler->getEnvironment()->getFilter($name);
23
+
24
+ $this->setAttribute('name', $name);
25
+ $this->setAttribute('type', 'filter');
26
+ $this->setAttribute('thing', $filter);
27
+ $this->setAttribute('needs_environment', $filter->needsEnvironment());
28
+ $this->setAttribute('needs_context', $filter->needsContext());
29
+ $this->setAttribute('arguments', $filter->getArguments());
30
+ if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) {
31
+ $this->setAttribute('callable', $filter->getCallable());
32
+ }
33
+
34
+ $this->compileCallable($compiler);
35
+ }
36
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Filter/Default.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Returns the value or the default value when it is undefined or empty.
14
+ *
15
+ * <pre>
16
+ * {{ var.foo|default('foo item on var is not defined') }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter
22
+ {
23
+ public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null)
24
+ {
25
+ $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine());
26
+
27
+ if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) {
28
+ $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine());
29
+ $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine());
30
+
31
+ $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine());
32
+ } else {
33
+ $node = $default;
34
+ }
35
+
36
+ parent::__construct($node, $filterName, $arguments, $lineno, $tag);
37
+ }
38
+
39
+ public function compile(Twig_Compiler $compiler)
40
+ {
41
+ $compiler->subcompile($this->getNode('node'));
42
+ }
43
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Function.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call
12
+ {
13
+ public function __construct($name, Twig_NodeInterface $arguments, $lineno)
14
+ {
15
+ parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno);
16
+ }
17
+
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $name = $this->getAttribute('name');
21
+ $function = $compiler->getEnvironment()->getFunction($name);
22
+
23
+ $this->setAttribute('name', $name);
24
+ $this->setAttribute('type', 'function');
25
+ $this->setAttribute('thing', $function);
26
+ $this->setAttribute('needs_environment', $function->needsEnvironment());
27
+ $this->setAttribute('needs_context', $function->needsContext());
28
+ $this->setAttribute('arguments', $function->getArguments());
29
+ if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) {
30
+ $this->setAttribute('callable', $function->getCallable());
31
+ }
32
+
33
+ $this->compileCallable($compiler);
34
+ }
35
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
15
+ {
16
+ parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) {
22
+ $compiler->raw('twig_template_get_attributes($this, ');
23
+ } else {
24
+ $compiler->raw('$this->getAttribute(');
25
+ }
26
+
27
+ if ($this->getAttribute('ignore_strict_check')) {
28
+ $this->getNode('node')->setAttribute('ignore_strict_check', true);
29
+ }
30
+
31
+ $compiler->subcompile($this->getNode('node'));
32
+
33
+ $compiler->raw(', ')->subcompile($this->getNode('attribute'));
34
+
35
+ if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
36
+ $compiler->raw(', ')->subcompile($this->getNode('arguments'));
37
+
38
+ if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
39
+ $compiler->raw(', ')->repr($this->getAttribute('type'));
40
+ }
41
+
42
+ if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
43
+ $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
44
+ }
45
+
46
+ if ($this->getAttribute('ignore_strict_check')) {
47
+ $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
48
+ }
49
+ }
50
+
51
+ $compiler->raw(')');
52
+ }
53
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/MethodCall.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2012 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_MethodCall extends Twig_Node_Expression
12
+ {
13
+ public function __construct(Twig_Node_Expression $node, $method, Twig_Node_Expression_Array $arguments, $lineno)
14
+ {
15
+ parent::__construct(array('node' => $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno);
16
+
17
+ if ($node instanceof Twig_Node_Expression_Name) {
18
+ $node->setAttribute('always_defined', true);
19
+ }
20
+ }
21
+
22
+ public function compile(Twig_Compiler $compiler)
23
+ {
24
+ $compiler
25
+ ->subcompile($this->getNode('node'))
26
+ ->raw('->')
27
+ ->raw($this->getAttribute('method'))
28
+ ->raw('(')
29
+ ;
30
+ $first = true;
31
+ foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) {
32
+ if (!$first) {
33
+ $compiler->raw(', ');
34
+ }
35
+ $first = false;
36
+
37
+ $compiler->subcompile($pair['value']);
38
+ }
39
+ $compiler->raw(')');
40
+ }
41
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Name.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Name extends Twig_Node_Expression
13
+ {
14
+ protected $specialVars = array(
15
+ '_self' => '$this',
16
+ '_context' => '$context',
17
+ '_charset' => '$this->env->getCharset()',
18
+ );
19
+
20
+ public function __construct($name, $lineno)
21
+ {
22
+ parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno);
23
+ }
24
+
25
+ public function compile(Twig_Compiler $compiler)
26
+ {
27
+ $name = $this->getAttribute('name');
28
+
29
+ if ($this->getAttribute('is_defined_test')) {
30
+ if ($this->isSpecial()) {
31
+ $compiler->repr(true);
32
+ } else {
33
+ $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)');
34
+ }
35
+ } elseif ($this->isSpecial()) {
36
+ $compiler->raw($this->specialVars[$name]);
37
+ } elseif ($this->getAttribute('always_defined')) {
38
+ $compiler
39
+ ->raw('$context[')
40
+ ->string($name)
41
+ ->raw(']')
42
+ ;
43
+ } else {
44
+ // remove the non-PHP 5.4 version when PHP 5.3 support is dropped
45
+ // as the non-optimized version is just a workaround for slow ternary operator
46
+ // when the context has a lot of variables
47
+ if (version_compare(phpversion(), '5.4.0RC1', '>=')) {
48
+ // PHP 5.4 ternary operator performance was optimized
49
+ $compiler
50
+ ->raw('(isset($context[')
51
+ ->string($name)
52
+ ->raw(']) ? $context[')
53
+ ->string($name)
54
+ ->raw('] : ')
55
+ ;
56
+
57
+ if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) {
58
+ $compiler->raw('null)');
59
+ } else {
60
+ $compiler->raw('$this->getContext($context, ')->string($name)->raw('))');
61
+ }
62
+ } else {
63
+ $compiler
64
+ ->raw('$this->getContext($context, ')
65
+ ->string($name)
66
+ ;
67
+
68
+ if ($this->getAttribute('ignore_strict_check')) {
69
+ $compiler->raw(', true');
70
+ }
71
+
72
+ $compiler
73
+ ->raw(')')
74
+ ;
75
+ }
76
+ }
77
+ }
78
+
79
+ public function isSpecial()
80
+ {
81
+ return isset($this->specialVars[$this->getAttribute('name')]);
82
+ }
83
+
84
+ public function isSimple()
85
+ {
86
+ return !$this->isSpecial() && !$this->getAttribute('is_defined_test');
87
+ }
88
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Parent.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a parent node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Expression_Parent extends Twig_Node_Expression
19
+ {
20
+ public function __construct($name, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ if ($this->getAttribute('output')) {
33
+ $compiler
34
+ ->addDebugInfo($this)
35
+ ->write("\$this->displayParentBlock(")
36
+ ->string($this->getAttribute('name'))
37
+ ->raw(", \$context, \$blocks);\n")
38
+ ;
39
+ } else {
40
+ $compiler
41
+ ->raw("\$this->renderParentBlock(")
42
+ ->string($this->getAttribute('name'))
43
+ ->raw(", \$context, \$blocks)")
44
+ ;
45
+ }
46
+ }
47
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/TempName.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_TempName extends Twig_Node_Expression
12
+ {
13
+ public function __construct($name, $lineno)
14
+ {
15
+ parent::__construct(array(), array('name' => $name), $lineno);
16
+ }
17
+
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $compiler
21
+ ->raw('$_')
22
+ ->raw($this->getAttribute('name'))
23
+ ->raw('_')
24
+ ;
25
+ }
26
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+ class Twig_Node_Expression_Test extends Twig_Node_Expression_Call
12
+ {
13
+ public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
14
+ {
15
+ parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno);
16
+ }
17
+
18
+ public function compile(Twig_Compiler $compiler)
19
+ {
20
+ $name = $this->getAttribute('name');
21
+ $test = $compiler->getEnvironment()->getTest($name);
22
+
23
+ $this->setAttribute('name', $name);
24
+ $this->setAttribute('type', 'test');
25
+ $this->setAttribute('thing', $test);
26
+ if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) {
27
+ $this->setAttribute('callable', $test->getCallable());
28
+ }
29
+
30
+ $this->compileCallable($compiler);
31
+ }
32
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is the exact same value as a constant.
14
+ *
15
+ * <pre>
16
+ * {% if post.status is constant('Post::PUBLISHED') %}
17
+ * the status attribute is exactly the same as Post::PUBLISHED
18
+ * {% endif %}
19
+ * </pre>
20
+ *
21
+ * @author Fabien Potencier <fabien@symfony.com>
22
+ */
23
+ class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test
24
+ {
25
+ public function compile(Twig_Compiler $compiler)
26
+ {
27
+ $compiler
28
+ ->raw('(')
29
+ ->subcompile($this->getNode('node'))
30
+ ->raw(' === constant(')
31
+ ;
32
+
33
+ if ($this->getNode('arguments')->hasNode(1)) {
34
+ $compiler
35
+ ->raw('get_class(')
36
+ ->subcompile($this->getNode('arguments')->getNode(1))
37
+ ->raw(')."::".')
38
+ ;
39
+ }
40
+
41
+ $compiler
42
+ ->subcompile($this->getNode('arguments')->getNode(0))
43
+ ->raw('))')
44
+ ;
45
+ }
46
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is defined in the current context.
14
+ *
15
+ * <pre>
16
+ * {# defined works with variable names and variable attributes #}
17
+ * {% if foo is defined %}
18
+ * {# ... #}
19
+ * {% endif %}
20
+ * </pre>
21
+ *
22
+ * @author Fabien Potencier <fabien@symfony.com>
23
+ */
24
+ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
25
+ {
26
+ public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno)
27
+ {
28
+ parent::__construct($node, $name, $arguments, $lineno);
29
+
30
+ if ($node instanceof Twig_Node_Expression_Name) {
31
+ $node->setAttribute('is_defined_test', true);
32
+ } elseif ($node instanceof Twig_Node_Expression_GetAttr) {
33
+ $node->setAttribute('is_defined_test', true);
34
+
35
+ $this->changeIgnoreStrictCheck($node);
36
+ } else {
37
+ throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine());
38
+ }
39
+ }
40
+
41
+ protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
42
+ {
43
+ $node->setAttribute('ignore_strict_check', true);
44
+
45
+ if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) {
46
+ $this->changeIgnoreStrictCheck($node->getNode('node'));
47
+ }
48
+ }
49
+
50
+ public function compile(Twig_Compiler $compiler)
51
+ {
52
+ $compiler->subcompile($this->getNode('node'));
53
+ }
54
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is divisible by a number.
14
+ *
15
+ * <pre>
16
+ * {% if loop.index is divisibleby(3) %}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(0 == ')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(' % ')
29
+ ->subcompile($this->getNode('arguments')->getNode(0))
30
+ ->raw(')')
31
+ ;
32
+ }
33
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Even.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a number is even.
14
+ *
15
+ * <pre>
16
+ * {{ var is even }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(' % 2 == 0')
29
+ ->raw(')')
30
+ ;
31
+ }
32
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Null.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks that a variable is null.
14
+ *
15
+ * <pre>
16
+ * {{ var is none }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(null === ')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(')')
29
+ ;
30
+ }
31
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Odd.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a number is odd.
14
+ *
15
+ * <pre>
16
+ * {{ var is odd }}
17
+ * </pre>
18
+ *
19
+ * @author Fabien Potencier <fabien@symfony.com>
20
+ */
21
+ class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test
22
+ {
23
+ public function compile(Twig_Compiler $compiler)
24
+ {
25
+ $compiler
26
+ ->raw('(')
27
+ ->subcompile($this->getNode('node'))
28
+ ->raw(' % 2 == 1')
29
+ ->raw(')')
30
+ ;
31
+ }
32
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Checks if a variable is the same as another one (=== in PHP).
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test
18
+ {
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler
22
+ ->raw('(')
23
+ ->subcompile($this->getNode('node'))
24
+ ->raw(' === ')
25
+ ->subcompile($this->getNode('arguments')->getNode(0))
26
+ ->raw(')')
27
+ ;
28
+ }
29
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression
13
+ {
14
+ public function __construct(Twig_NodeInterface $node, $lineno)
15
+ {
16
+ parent::__construct(array('node' => $node), array(), $lineno);
17
+ }
18
+
19
+ public function compile(Twig_Compiler $compiler)
20
+ {
21
+ $compiler->raw('(');
22
+ $this->operator($compiler);
23
+ $compiler
24
+ ->subcompile($this->getNode('node'))
25
+ ->raw(')')
26
+ ;
27
+ }
28
+
29
+ abstract public function operator(Twig_Compiler $compiler);
30
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ $compiler->raw('-');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Not.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ $compiler->raw('!');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+ class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary
13
+ {
14
+ public function operator(Twig_Compiler $compiler)
15
+ {
16
+ $compiler->raw('+');
17
+ }
18
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Flush.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a flush node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Flush extends Twig_Node
18
+ {
19
+ public function __construct($lineno, $tag)
20
+ {
21
+ parent::__construct(array(), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write("flush();\n")
34
+ ;
35
+ }
36
+ }
vendor/vendor/twig/twig/lib/Twig/Node/For.php ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a for node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_For extends Twig_Node
19
+ {
20
+ protected $loop;
21
+
22
+ public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
23
+ {
24
+ $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag)));
25
+
26
+ if (null !== $ifexpr) {
27
+ $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag);
28
+ }
29
+
30
+ parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag);
31
+ }
32
+
33
+ /**
34
+ * Compiles the node to PHP.
35
+ *
36
+ * @param Twig_Compiler A Twig_Compiler instance
37
+ */
38
+ public function compile(Twig_Compiler $compiler)
39
+ {
40
+ $compiler
41
+ ->addDebugInfo($this)
42
+ // the (array) cast bypasses a PHP 5.2.6 bug
43
+ ->write("\$context['_parent'] = (array) \$context;\n")
44
+ ->write("\$context['_seq'] = twig_ensure_traversable(")
45
+ ->subcompile($this->getNode('seq'))
46
+ ->raw(");\n")
47
+ ;
48
+
49
+ if (null !== $this->getNode('else')) {
50
+ $compiler->write("\$context['_iterated'] = false;\n");
51
+ }
52
+
53
+ if ($this->getAttribute('with_loop')) {
54
+ $compiler
55
+ ->write("\$context['loop'] = array(\n")
56
+ ->write(" 'parent' => \$context['_parent'],\n")
57
+ ->write(" 'index0' => 0,\n")
58
+ ->write(" 'index' => 1,\n")
59
+ ->write(" 'first' => true,\n")
60
+ ->write(");\n")
61
+ ;
62
+
63
+ if (!$this->getAttribute('ifexpr')) {
64
+ $compiler
65
+ ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
66
+ ->indent()
67
+ ->write("\$length = count(\$context['_seq']);\n")
68
+ ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
69
+ ->write("\$context['loop']['revindex'] = \$length;\n")
70
+ ->write("\$context['loop']['length'] = \$length;\n")
71
+ ->write("\$context['loop']['last'] = 1 === \$length;\n")
72
+ ->outdent()
73
+ ->write("}\n")
74
+ ;
75
+ }
76
+ }
77
+
78
+ $this->loop->setAttribute('else', null !== $this->getNode('else'));
79
+ $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop'));
80
+ $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr'));
81
+
82
+ $compiler
83
+ ->write("foreach (\$context['_seq'] as ")
84
+ ->subcompile($this->getNode('key_target'))
85
+ ->raw(" => ")
86
+ ->subcompile($this->getNode('value_target'))
87
+ ->raw(") {\n")
88
+ ->indent()
89
+ ->subcompile($this->getNode('body'))
90
+ ->outdent()
91
+ ->write("}\n")
92
+ ;
93
+
94
+ if (null !== $this->getNode('else')) {
95
+ $compiler
96
+ ->write("if (!\$context['_iterated']) {\n")
97
+ ->indent()
98
+ ->subcompile($this->getNode('else'))
99
+ ->outdent()
100
+ ->write("}\n")
101
+ ;
102
+ }
103
+
104
+ $compiler->write("\$_parent = \$context['_parent'];\n");
105
+
106
+ // remove some "private" loop variables (needed for nested loops)
107
+ $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
108
+
109
+ // keep the values set in the inner context for variables defined in the outer context
110
+ $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n");
111
+ }
112
+ }
vendor/vendor/twig/twig/lib/Twig/Node/ForLoop.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2011 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Internal node used by the for node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_ForLoop extends Twig_Node
18
+ {
19
+ public function __construct($lineno, $tag = null)
20
+ {
21
+ parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ if ($this->getAttribute('else')) {
32
+ $compiler->write("\$context['_iterated'] = true;\n");
33
+ }
34
+
35
+ if ($this->getAttribute('with_loop')) {
36
+ $compiler
37
+ ->write("++\$context['loop']['index0'];\n")
38
+ ->write("++\$context['loop']['index'];\n")
39
+ ->write("\$context['loop']['first'] = false;\n")
40
+ ;
41
+
42
+ if (!$this->getAttribute('ifexpr')) {
43
+ $compiler
44
+ ->write("if (isset(\$context['loop']['length'])) {\n")
45
+ ->indent()
46
+ ->write("--\$context['loop']['revindex0'];\n")
47
+ ->write("--\$context['loop']['revindex'];\n")
48
+ ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
49
+ ->outdent()
50
+ ->write("}\n")
51
+ ;
52
+ }
53
+ }
54
+ }
55
+ }
vendor/vendor/twig/twig/lib/Twig/Node/If.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents an if node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_If extends Twig_Node
19
+ {
20
+ public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler->addDebugInfo($this);
33
+ for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) {
34
+ if ($i > 0) {
35
+ $compiler
36
+ ->outdent()
37
+ ->write("} elseif (")
38
+ ;
39
+ } else {
40
+ $compiler
41
+ ->write('if (')
42
+ ;
43
+ }
44
+
45
+ $compiler
46
+ ->subcompile($this->getNode('tests')->getNode($i))
47
+ ->raw(") {\n")
48
+ ->indent()
49
+ ->subcompile($this->getNode('tests')->getNode($i + 1))
50
+ ;
51
+ }
52
+
53
+ if ($this->hasNode('else') && null !== $this->getNode('else')) {
54
+ $compiler
55
+ ->outdent()
56
+ ->write("} else {\n")
57
+ ->indent()
58
+ ->subcompile($this->getNode('else'))
59
+ ;
60
+ }
61
+
62
+ $compiler
63
+ ->outdent()
64
+ ->write("}\n");
65
+ }
66
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Import.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents an import node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Import extends Twig_Node
18
+ {
19
+ public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write('')
34
+ ->subcompile($this->getNode('var'))
35
+ ->raw(' = ')
36
+ ;
37
+
38
+ if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) {
39
+ $compiler->raw("\$this");
40
+ } else {
41
+ $compiler
42
+ ->raw('$this->env->loadTemplate(')
43
+ ->subcompile($this->getNode('expr'))
44
+ ->raw(")")
45
+ ;
46
+ }
47
+
48
+ $compiler->raw(";\n");
49
+ }
50
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Include.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents an include node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler->addDebugInfo($this);
33
+
34
+ if ($this->getAttribute('ignore_missing')) {
35
+ $compiler
36
+ ->write("try {\n")
37
+ ->indent()
38
+ ;
39
+ }
40
+
41
+ $this->addGetTemplate($compiler);
42
+
43
+ $compiler->raw('->display(');
44
+
45
+ $this->addTemplateArguments($compiler);
46
+
47
+ $compiler->raw(");\n");
48
+
49
+ if ($this->getAttribute('ignore_missing')) {
50
+ $compiler
51
+ ->outdent()
52
+ ->write("} catch (Twig_Error_Loader \$e) {\n")
53
+ ->indent()
54
+ ->write("// ignore missing template\n")
55
+ ->outdent()
56
+ ->write("}\n\n")
57
+ ;
58
+ }
59
+ }
60
+
61
+ protected function addGetTemplate(Twig_Compiler $compiler)
62
+ {
63
+ if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
64
+ $compiler
65
+ ->write("\$this->env->loadTemplate(")
66
+ ->subcompile($this->getNode('expr'))
67
+ ->raw(")")
68
+ ;
69
+ } else {
70
+ $compiler
71
+ ->write("\$template = \$this->env->resolveTemplate(")
72
+ ->subcompile($this->getNode('expr'))
73
+ ->raw(");\n")
74
+ ->write('$template')
75
+ ;
76
+ }
77
+ }
78
+
79
+ protected function addTemplateArguments(Twig_Compiler $compiler)
80
+ {
81
+ if (false === $this->getAttribute('only')) {
82
+ if (null === $this->getNode('variables')) {
83
+ $compiler->raw('$context');
84
+ } else {
85
+ $compiler
86
+ ->raw('array_merge($context, ')
87
+ ->subcompile($this->getNode('variables'))
88
+ ->raw(')')
89
+ ;
90
+ }
91
+ } else {
92
+ if (null === $this->getNode('variables')) {
93
+ $compiler->raw('array()');
94
+ } else {
95
+ $compiler->subcompile($this->getNode('variables'));
96
+ }
97
+ }
98
+ }
99
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Macro.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a macro node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Macro extends Twig_Node
18
+ {
19
+ public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write(sprintf("public function get%s(", $this->getAttribute('name')))
34
+ ;
35
+
36
+ $count = count($this->getNode('arguments'));
37
+ $pos = 0;
38
+ foreach ($this->getNode('arguments') as $name => $default) {
39
+ $compiler
40
+ ->raw('$_'.$name.' = ')
41
+ ->subcompile($default)
42
+ ;
43
+
44
+ if (++$pos < $count) {
45
+ $compiler->raw(', ');
46
+ }
47
+ }
48
+
49
+ $compiler
50
+ ->raw(")\n")
51
+ ->write("{\n")
52
+ ->indent()
53
+ ;
54
+
55
+ if (!count($this->getNode('arguments'))) {
56
+ $compiler->write("\$context = \$this->env->getGlobals();\n\n");
57
+ } else {
58
+ $compiler
59
+ ->write("\$context = \$this->env->mergeGlobals(array(\n")
60
+ ->indent()
61
+ ;
62
+
63
+ foreach ($this->getNode('arguments') as $name => $default) {
64
+ $compiler
65
+ ->write('')
66
+ ->string($name)
67
+ ->raw(' => $_'.$name)
68
+ ->raw(",\n")
69
+ ;
70
+ }
71
+
72
+ $compiler
73
+ ->outdent()
74
+ ->write("));\n\n")
75
+ ;
76
+ }
77
+
78
+ $compiler
79
+ ->write("\$blocks = array();\n\n")
80
+ ->write("ob_start();\n")
81
+ ->write("try {\n")
82
+ ->indent()
83
+ ->subcompile($this->getNode('body'))
84
+ ->outdent()
85
+ ->write("} catch (Exception \$e) {\n")
86
+ ->indent()
87
+ ->write("ob_end_clean();\n\n")
88
+ ->write("throw \$e;\n")
89
+ ->outdent()
90
+ ->write("}\n\n")
91
+ ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n")
92
+ ->outdent()
93
+ ->write("}\n\n")
94
+ ;
95
+ }
96
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Module.php ADDED
@@ -0,0 +1,383 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a module node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Module extends Twig_Node
19
+ {
20
+ public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
21
+ {
22
+ // embedded templates are set as attributes so that they are only visited once by the visitors
23
+ parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1);
24
+ }
25
+
26
+ public function setIndex($index)
27
+ {
28
+ $this->setAttribute('index', $index);
29
+ }
30
+
31
+ /**
32
+ * Compiles the node to PHP.
33
+ *
34
+ * @param Twig_Compiler A Twig_Compiler instance
35
+ */
36
+ public function compile(Twig_Compiler $compiler)
37
+ {
38
+ $this->compileTemplate($compiler);
39
+
40
+ foreach ($this->getAttribute('embedded_templates') as $template) {
41
+ $compiler->subcompile($template);
42
+ }
43
+ }
44
+
45
+ protected function compileTemplate(Twig_Compiler $compiler)
46
+ {
47
+ if (!$this->getAttribute('index')) {
48
+ $compiler->write('<?php');
49
+ }
50
+
51
+ $this->compileClassHeader($compiler);
52
+
53
+ if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
54
+ $this->compileConstructor($compiler);
55
+ }
56
+
57
+ $this->compileGetParent($compiler);
58
+
59
+ $this->compileDisplayHeader($compiler);
60
+
61
+ $this->compileDisplayBody($compiler);
62
+
63
+ $this->compileDisplayFooter($compiler);
64
+
65
+ $compiler->subcompile($this->getNode('blocks'));
66
+
67
+ $this->compileMacros($compiler);
68
+
69
+ $this->compileGetTemplateName($compiler);
70
+
71
+ $this->compileIsTraitable($compiler);
72
+
73
+ $this->compileDebugInfo($compiler);
74
+
75
+ $this->compileClassFooter($compiler);
76
+ }
77
+
78
+ protected function compileGetParent(Twig_Compiler $compiler)
79
+ {
80
+ if (null === $this->getNode('parent')) {
81
+ return;
82
+ }
83
+
84
+ $compiler
85
+ ->write("protected function doGetParent(array \$context)\n", "{\n")
86
+ ->indent()
87
+ ->write("return ")
88
+ ;
89
+
90
+ if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
91
+ $compiler->subcompile($this->getNode('parent'));
92
+ } else {
93
+ $compiler
94
+ ->raw("\$this->env->resolveTemplate(")
95
+ ->subcompile($this->getNode('parent'))
96
+ ->raw(")")
97
+ ;
98
+ }
99
+
100
+ $compiler
101
+ ->raw(";\n")
102
+ ->outdent()
103
+ ->write("}\n\n")
104
+ ;
105
+ }
106
+
107
+ protected function compileDisplayBody(Twig_Compiler $compiler)
108
+ {
109
+ $compiler->subcompile($this->getNode('body'));
110
+
111
+ if (null !== $this->getNode('parent')) {
112
+ if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
113
+ $compiler->write("\$this->parent");
114
+ } else {
115
+ $compiler->write("\$this->getParent(\$context)");
116
+ }
117
+ $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
118
+ }
119
+ }
120
+
121
+ protected function compileClassHeader(Twig_Compiler $compiler)
122
+ {
123
+ $compiler
124
+ ->write("\n\n")
125
+ // if the filename contains */, add a blank to avoid a PHP parse error
126
+ ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
127
+ ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
128
+ ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
129
+ ->write("{\n")
130
+ ->indent()
131
+ ;
132
+ }
133
+
134
+ protected function compileConstructor(Twig_Compiler $compiler)
135
+ {
136
+ $compiler
137
+ ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
138
+ ->indent()
139
+ ->write("parent::__construct(\$env);\n\n")
140
+ ;
141
+
142
+ // parent
143
+ if (null === $this->getNode('parent')) {
144
+ $compiler->write("\$this->parent = false;\n\n");
145
+ } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
146
+ $compiler
147
+ ->write("\$this->parent = \$this->env->loadTemplate(")
148
+ ->subcompile($this->getNode('parent'))
149
+ ->raw(");\n\n")
150
+ ;
151
+ }
152
+
153
+ $countTraits = count($this->getNode('traits'));
154
+ if ($countTraits) {
155
+ // traits
156
+ foreach ($this->getNode('traits') as $i => $trait) {
157
+ $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
158
+
159
+ $compiler
160
+ ->addDebugInfo($trait->getNode('template'))
161
+ ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
162
+ ->indent()
163
+ ->write("throw new Twig_Error_Runtime('Template \"'.")
164
+ ->subcompile($trait->getNode('template'))
165
+ ->raw(".'\" cannot be used as a trait.');\n")
166
+ ->outdent()
167
+ ->write("}\n")
168
+ ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
169
+ ;
170
+
171
+ foreach ($trait->getNode('targets') as $key => $value) {
172
+ $compiler
173
+ ->write(sprintf("if (!isset(\$_trait_%s_blocks[", $i))
174
+ ->string($key)
175
+ ->raw("])) {\n")
176
+ ->indent()
177
+ ->write("throw new Twig_Error_Runtime(sprintf('Block ")
178
+ ->string($key)
179
+ ->raw(" is not defined in trait ")
180
+ ->subcompile($trait->getNode('template'))
181
+ ->raw(".'));\n")
182
+ ->outdent()
183
+ ->write("}\n\n")
184
+
185
+ ->write(sprintf("\$_trait_%s_blocks[", $i))
186
+ ->subcompile($value)
187
+ ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
188
+ ->string($key)
189
+ ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
190
+ ->string($key)
191
+ ->raw("]);\n\n")
192
+ ;
193
+ }
194
+ }
195
+
196
+ if ($countTraits > 1) {
197
+ $compiler
198
+ ->write("\$this->traits = array_merge(\n")
199
+ ->indent()
200
+ ;
201
+
202
+ for ($i = 0; $i < $countTraits; $i++) {
203
+ $compiler
204
+ ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
205
+ ;
206
+ }
207
+
208
+ $compiler
209
+ ->outdent()
210
+ ->write(");\n\n")
211
+ ;
212
+ } else {
213
+ $compiler
214
+ ->write("\$this->traits = \$_trait_0_blocks;\n\n")
215
+ ;
216
+ }
217
+
218
+ $compiler
219
+ ->write("\$this->blocks = array_merge(\n")
220
+ ->indent()
221
+ ->write("\$this->traits,\n")
222
+ ->write("array(\n")
223
+ ;
224
+ } else {
225
+ $compiler
226
+ ->write("\$this->blocks = array(\n")
227
+ ;
228
+ }
229
+
230
+ // blocks
231
+ $compiler
232
+ ->indent()
233
+ ;
234
+
235
+ foreach ($this->getNode('blocks') as $name => $node) {
236
+ $compiler
237
+ ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
238
+ ;
239
+ }
240
+
241
+ if ($countTraits) {
242
+ $compiler
243
+ ->outdent()
244
+ ->write(")\n")
245
+ ;
246
+ }
247
+
248
+ $compiler
249
+ ->outdent()
250
+ ->write(");\n")
251
+ ->outdent()
252
+ ->write("}\n\n");
253
+ ;
254
+ }
255
+
256
+ protected function compileDisplayHeader(Twig_Compiler $compiler)
257
+ {
258
+ $compiler
259
+ ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
260
+ ->indent()
261
+ ;
262
+ }
263
+
264
+ protected function compileDisplayFooter(Twig_Compiler $compiler)
265
+ {
266
+ $compiler
267
+ ->outdent()
268
+ ->write("}\n\n")
269
+ ;
270
+ }
271
+
272
+ protected function compileClassFooter(Twig_Compiler $compiler)
273
+ {
274
+ $compiler
275
+ ->outdent()
276
+ ->write("}\n")
277
+ ;
278
+ }
279
+
280
+ protected function compileMacros(Twig_Compiler $compiler)
281
+ {
282
+ $compiler->subcompile($this->getNode('macros'));
283
+ }
284
+
285
+ protected function compileGetTemplateName(Twig_Compiler $compiler)
286
+ {
287
+ $compiler
288
+ ->write("public function getTemplateName()\n", "{\n")
289
+ ->indent()
290
+ ->write('return ')
291
+ ->repr($this->getAttribute('filename'))
292
+ ->raw(";\n")
293
+ ->outdent()
294
+ ->write("}\n\n")
295
+ ;
296
+ }
297
+
298
+ protected function compileIsTraitable(Twig_Compiler $compiler)
299
+ {
300
+ // A template can be used as a trait if:
301
+ // * it has no parent
302
+ // * it has no macros
303
+ // * it has no body
304
+ //
305
+ // Put another way, a template can be used as a trait if it
306
+ // only contains blocks and use statements.
307
+ $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
308
+ if ($traitable) {
309
+ if ($this->getNode('body') instanceof Twig_Node_Body) {
310
+ $nodes = $this->getNode('body')->getNode(0);
311
+ } else {
312
+ $nodes = $this->getNode('body');
313
+ }
314
+
315
+ if (!count($nodes)) {
316
+ $nodes = new Twig_Node(array($nodes));
317
+ }
318
+
319
+ foreach ($nodes as $node) {
320
+ if (!count($node)) {
321
+ continue;
322
+ }
323
+
324
+ if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
325
+ continue;
326
+ }
327
+
328
+ if ($node instanceof Twig_Node_BlockReference) {
329
+ continue;
330
+ }
331
+
332
+ $traitable = false;
333
+ break;
334
+ }
335
+ }
336
+
337
+ if ($traitable) {
338
+ return;
339
+ }
340
+
341
+ $compiler
342
+ ->write("public function isTraitable()\n", "{\n")
343
+ ->indent()
344
+ ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
345
+ ->outdent()
346
+ ->write("}\n\n")
347
+ ;
348
+ }
349
+
350
+ protected function compileDebugInfo(Twig_Compiler $compiler)
351
+ {
352
+ $compiler
353
+ ->write("public function getDebugInfo()\n", "{\n")
354
+ ->indent()
355
+ ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
356
+ ->outdent()
357
+ ->write("}\n")
358
+ ;
359
+ }
360
+
361
+ protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
362
+ {
363
+ if ($node instanceof Twig_Node_Expression_Constant) {
364
+ $compiler
365
+ ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
366
+ ->subcompile($node)
367
+ ->raw(");\n")
368
+ ;
369
+ } else {
370
+ $compiler
371
+ ->write(sprintf("%s = ", $var))
372
+ ->subcompile($node)
373
+ ->raw(";\n")
374
+ ->write(sprintf("if (!%s", $var))
375
+ ->raw(" instanceof Twig_Template) {\n")
376
+ ->indent()
377
+ ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
378
+ ->outdent()
379
+ ->write("}\n")
380
+ ;
381
+ }
382
+ }
383
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Print.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a node that outputs an expression.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
19
+ {
20
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
21
+ {
22
+ parent::__construct(array('expr' => $expr), array(), $lineno, $tag);
23
+ }
24
+
25
+ /**
26
+ * Compiles the node to PHP.
27
+ *
28
+ * @param Twig_Compiler A Twig_Compiler instance
29
+ */
30
+ public function compile(Twig_Compiler $compiler)
31
+ {
32
+ $compiler
33
+ ->addDebugInfo($this)
34
+ ->write('echo ')
35
+ ->subcompile($this->getNode('expr'))
36
+ ->raw(";\n")
37
+ ;
38
+ }
39
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Sandbox.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a sandbox node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Sandbox extends Twig_Node
18
+ {
19
+ public function __construct(Twig_NodeInterface $body, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('body' => $body), array(), $lineno, $tag);
22
+ }
23
+
24
+ /**
25
+ * Compiles the node to PHP.
26
+ *
27
+ * @param Twig_Compiler A Twig_Compiler instance
28
+ */
29
+ public function compile(Twig_Compiler $compiler)
30
+ {
31
+ $compiler
32
+ ->addDebugInfo($this)
33
+ ->write("\$sandbox = \$this->env->getExtension('sandbox');\n")
34
+ ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n")
35
+ ->indent()
36
+ ->write("\$sandbox->enableSandbox();\n")
37
+ ->outdent()
38
+ ->write("}\n")
39
+ ->subcompile($this->getNode('body'))
40
+ ->write("if (!\$alreadySandboxed) {\n")
41
+ ->indent()
42
+ ->write("\$sandbox->disableSandbox();\n")
43
+ ->outdent()
44
+ ->write("}\n")
45
+ ;
46
+ }
47
+ }
vendor/vendor/twig/twig/lib/Twig/Node/SandboxedModule.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2009 Fabien Potencier
7
+ * (c) 2009 Armin Ronacher
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ /**
14
+ * Represents a module node.
15
+ *
16
+ * @author Fabien Potencier <fabien@symfony.com>
17
+ */
18
+ class Twig_Node_SandboxedModule extends Twig_Node_Module
19
+ {
20
+ protected $usedFilters;
21
+ protected $usedTags;
22
+ protected $usedFunctions;
23
+
24
+ public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
25
+ {
26
+ parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
27
+
28
+ $this->setAttribute('index', $node->getAttribute('index'));
29
+
30
+ $this->usedFilters = $usedFilters;
31
+ $this->usedTags = $usedTags;
32
+ $this->usedFunctions = $usedFunctions;
33
+ }
34
+
35
+ protected function compileDisplayBody(Twig_Compiler $compiler)
36
+ {
37
+ $compiler->write("\$this->checkSecurity();\n");
38
+
39
+ parent::compileDisplayBody($compiler);
40
+ }
41
+
42
+ protected function compileDisplayFooter(Twig_Compiler $compiler)
43
+ {
44
+ parent::compileDisplayFooter($compiler);
45
+
46
+ $compiler
47
+ ->write("protected function checkSecurity()\n", "{\n")
48
+ ->indent()
49
+ ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
50
+ ->indent()
51
+ ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
52
+ ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
53
+ ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
54
+ ->outdent()
55
+ ->write(");\n")
56
+ ->outdent()
57
+ ->write("}\n\n")
58
+ ;
59
+ }
60
+ }
vendor/vendor/twig/twig/lib/Twig/Node/SandboxedPrint.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Twig_Node_SandboxedPrint adds a check for the __toString() method
14
+ * when the variable is an object and the sandbox is activated.
15
+ *
16
+ * When there is a simple Print statement, like {{ article }},
17
+ * and if the sandbox is enabled, we need to check that the __toString()
18
+ * method is allowed if 'article' is an object.
19
+ *
20
+ * @author Fabien Potencier <fabien@symfony.com>
21
+ */
22
+ class Twig_Node_SandboxedPrint extends Twig_Node_Print
23
+ {
24
+ public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null)
25
+ {
26
+ parent::__construct($expr, $lineno, $tag);
27
+ }
28
+
29
+ /**
30
+ * Compiles the node to PHP.
31
+ *
32
+ * @param Twig_Compiler A Twig_Compiler instance
33
+ */
34
+ public function compile(Twig_Compiler $compiler)
35
+ {
36
+ $compiler
37
+ ->addDebugInfo($this)
38
+ ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(')
39
+ ->subcompile($this->getNode('expr'))
40
+ ->raw(");\n")
41
+ ;
42
+ }
43
+
44
+ /**
45
+ * Removes node filters.
46
+ *
47
+ * This is mostly needed when another visitor adds filters (like the escaper one).
48
+ *
49
+ * @param Twig_Node $node A Node
50
+ */
51
+ protected function removeNodeFilter($node)
52
+ {
53
+ if ($node instanceof Twig_Node_Expression_Filter) {
54
+ return $this->removeNodeFilter($node->getNode('node'));
55
+ }
56
+
57
+ return $node;
58
+ }
59
+ }
vendor/vendor/twig/twig/lib/Twig/Node/Set.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Twig.
5
+ *
6
+ * (c) 2010 Fabien Potencier
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */
11
+
12
+ /**
13
+ * Represents a set node.
14
+ *
15
+ * @author Fabien Potencier <fabien@symfony.com>
16
+ */
17
+ class Twig_Node_Set extends Twig_Node
18
+ {
19
+ public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null)
20
+ {
21
+ parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag);
22
+
23
+ /*
24
+ * Optimizes the node when capture is used for a large block of text.
25
+ *
26
+ * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo");
27
+ */
28
+ if ($this->getAttribute('capture')) {
29
+ $this->setAttribute('safe', true);
30
+
31
+ $values = $this->getNode('values');
32
+ if ($values instanceof Twig_Node_Text) {
33
+ $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine()));
34
+ $this->setAttribute('capture', false);
35
+ }
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Compiles the node to PHP.
41
+ *
42
+ * @param Twig_Compiler A Twig_Compiler instance
43
+ */
44
+ public function compile(Twig_Compiler $compiler)
45
+ {
46
+ $compiler->addDebugInfo($this);
47
+
48
+ if (count($this->getNode('names')) > 1) {
49
+ $compiler->write('list(');
50
+ foreach ($this->getNode('names') as $idx => $node) {
51
+ if ($idx) {
52
+ $compiler->raw(', ');
53
+ }
54
+
55
+ $compiler->subcompile($node);
56
+ }
57
+ $compiler->raw(')');
58
+ } else {
59
+ if ($this->getAttribute('capture')) {
60
+ $compiler
61
+ ->write("ob_star