PageRenderTime 60ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/system/cms/libraries/Lex/README.md

https://github.com/marcoscoelho/pyrocms
Markdown | 370 lines | 256 code | 114 blank | 0 comment | 0 complexity | e30420fd628fa7c6ed81ef1ee7f793b1 MD5 | raw file
  1. Lex
  2. ===
  3. Lex is a lightweight template parser.
  4. _Lex is released under the MIT License and is Copyrighted 2011 Dan Horrigan._
  5. Basic Usage
  6. ===========
  7. Including Lex
  8. -------------
  9. Lex includes a basic autoloader to load it's classes.
  10. include 'lib/Lex/Autoloader.php';
  11. Lex_Autoloader::register();
  12. Using Lex
  13. ---------
  14. Basic parsing of a file:
  15. $parser = new Lex_Parser();
  16. $template = $parser->parse(file_get_contents('template.lex'), $data);
  17. You can also set the Scope Glue (see "Scope Glue" under Syntax below):
  18. $parser = new Lex_Parser();
  19. $parser->scope_glue(':');
  20. $template = $parser->parse(file_get_contents('template.lex'), $data);
  21. To allow noparse extractions to accumulate so they don't get parsed by a later call to the parser set cumulative_noparse to true:
  22. $parser = new Lex_Parser();
  23. $parser->cumulative_noparse(true);
  24. $template = $parser->parse(file_get_contents('template.lex'), $data);
  25. // Second parse on the same text somewhere else in your app
  26. $template = $parser->parse($template, $data);
  27. // Now that all parsing is done we inject the contents between the {{ noparse }} tags back into the template text
  28. Lex_Parser::inject_noparse($template);
  29. If you only want to parse a data array and not worry about callback tags or comments, you can do use the `parse_variables()` method:
  30. $parser = new Lex_Parser();
  31. $template = $parser->parse_variables(file_get_contents('template.lex'), $data);
  32. ### PHP in Templates
  33. By default PHP is encoded, and not executed. This is for security reasons. However, you may at times want to enable it. To do that simply send `true` as the fourth parameter to your `parse()` call.
  34. $parser = new Lex_Parser();
  35. $template = $parser->parse(file_get_contents('template.lex'), $data, $callback, true);
  36. Syntax
  37. ======
  38. General
  39. -------
  40. All Lex code is delimeted by double curly braces (`{{ }}`). These delimeters were chosen to reduce the chance of conflicts with JavaScript and CSS.
  41. Here is an example of some Lex template code:
  42. Hello, {{name}}
  43. Scope Glue
  44. ----------
  45. Scope Glue is/are the character(s) used by Lex to trigger a scope change. A scope change is what happens when, for instance, you are accessing a nested variable inside and array/object, or when scoping a custom callback tag.
  46. By default a dot (`.`) is used as the Scope Glue, although you can select any character(s).
  47. Whitespace
  48. ----------
  49. Whitespace before or after the delimeters is allowed, however, in certain cases, whitespace within the tag is prohibited (explained in the following sections).
  50. **Some valid examples:**
  51. {{ name }}
  52. {{name }}
  53. {{ name}}
  54. {{ name }}
  55. {{
  56. name
  57. }}
  58. **Some invalid examples:**
  59. {{ na me }}
  60. { {name} }
  61. Comments
  62. --------
  63. You can add comments to your templates by wrapping the text in `{{# #}}`.
  64. **Example**
  65. {{# This will not be parsed or shown in the resulting HTML #}}
  66. {{#
  67. They can be multi-line too.
  68. #}}
  69. Prevent Parsing
  70. ---------------
  71. You can prevent the parser from parsing blocks of code by wrapping it in `{{ noparse }}{{ /noparse }}` tags.
  72. **Example**
  73. {{ noparse }}
  74. Hello, {{ name }}!
  75. {{ /noparse }}
  76. Variable Tags
  77. -------------
  78. When dealing with variables, you can: access single variables, access deeply nested variables inside arrays/objects, and loop over an array. You can even loop over nested arrays.
  79. ### Simple Variable Tags
  80. For our basic examples, lets assume you have the following array of variables (sent to the parser):
  81. array(
  82. 'title' => 'Lex is Awesome!',
  83. 'name' => 'World',
  84. 'real_name' => array(
  85. 'first' => 'Lex',
  86. 'last' => 'Luther',
  87. )
  88. )
  89. **Basic Example:**
  90. {{# Parsed: Hello, World! #}}
  91. Hello, {{ name }}!
  92. {{# Parsed: <h1>Lex is Awesome!</h1> #}}
  93. <h1>{{ title }}</h1>
  94. {{# Parsed: My real name is Lex Luther!</h1> #}}
  95. My real name is {{ real_name.first }} {{ real_name.last }}
  96. The `{{ real_name.first }}` and `{{ real_name.last }}` tags check if `real_name` exists, then check if `first` and `last` respectively exist inside the `real_name` array/object then returns it.
  97. ### Looped Variable Tags
  98. Looped Variable tags are just like Simple Variable tags, except they correspond to an array of arrays/objects, which is looped over.
  99. A Looped Variable tag is a closed tag which wraps the looped content. The closing tag must match the opening tag exactly, except it must be prefixed with a forward slash (`/`). There can be **no** whitespace between the forward slash and the tag name (whitespace before the forward slash is allowed).
  100. **Valid Example:**
  101. {{ projects }} Some Content Here {{ /projects }}
  102. **Invalid Example:**
  103. {{ projects }} Some Content Here {{/ projects }}
  104. The looped content is what is contained between the opening and closing tags. This content is looped through and output for every item in the looped array.
  105. When in a Looped Tag you have access to any sub-variables for the current element in the loop.
  106. In the following example, let's assume you have the following array/object of variables:
  107. array(
  108. 'title' => 'Current Projects',
  109. 'projects' => array(
  110. array(
  111. 'name' => 'Acme Site',
  112. 'assignees' => array(
  113. array('name' => 'Dan'),
  114. array('name' => 'Phil'),
  115. ),
  116. ),
  117. array(
  118. 'name' => 'Lex',
  119. 'contributors' => array(
  120. array('name' => 'Dan'),
  121. array('name' => 'Ziggy'),
  122. array('name' => 'Jerel')
  123. ),
  124. ),
  125. ),
  126. )
  127. In the template, we will want to display the title, followed by a list of projects and their assignees.
  128. <h1>{{ title }}</h1>
  129. {{ projects }}
  130. <h3>{{ name }}</h3>
  131. <h4>Assignees</h4>
  132. <ul>
  133. {{ assignees }}
  134. <li>{{ name }}</li>
  135. {{ /assignees }}
  136. </ul>
  137. {{ /projects }}
  138. As you can see inside each project element we have access to that project's assignees. You can also see that you can loop over sub-values, exactly like you can any other array.
  139. Conditionals
  140. -------------
  141. Conditionals in Lex are simple and easy to use. It allows for the standard `if`, `elseif`, and `else`.
  142. All `if` blocks must be closed with either a `{{ /if }}` or `{{ endif }}` tag.
  143. Variables inside of if Conditionals, do not, and should not, use the Tag delimeters (it will cause wierd issues with your output).
  144. A Conditional can contain any Comparison Operators you would do in PHP (`==`, `!=`, `===`, `!==`, `>`, `<`, `<=`, `>=`). You can also use any of the Logical Operators (`!`, `||`, `&&`, `and`, `or`).
  145. **Examples**
  146. {{ if show_name }}
  147. <p>My name is {{real_name.first}} {{real_name.last}}</p>
  148. {{ endif }}
  149. {{ if user.group == 'admin' }}
  150. <p>You are an Admin!</p>
  151. {{ elseif user.group == 'user' }}
  152. <p>You are a normal User.</p>
  153. {{ else }}
  154. <p>I don't know what you are.</p>
  155. {{ endif }}
  156. {{ if show_real_name }}
  157. <p>My name is {{real_name.first}} {{real_name.last}}</p>
  158. {{ else }}
  159. <p>My name is John Doe</p>
  160. {{ endif }}
  161. ### Callback Tags in Conditionals
  162. Using a callback tag in a conditional is simple. Use it just like any other variable except for one exception. When you need to provide attributes for the callback tag, you are required to surround the tag with a ***single*** set of braces (you can optionally use them for all callback tags).
  163. **Examples**
  164. {{ if user.logged_in }} {{ endif }}
  165. {{ if user.logged_in and {user.is_group group="admin"} }} {{ endif }}
  166. Callback Tags
  167. -------------
  168. Callback tags allow you to have tags with attributes that get sent through a callback. This makes it easy to create a nice plugin system.
  169. Here is an example
  170. {{ template.partial name="navigation" }}
  171. You can also close the tag to make it a **Callback Block**:
  172. {{ template.partial name="navigation" }}
  173. {{ /template.partial }}
  174. Note that attributes are not required. When no attributes are given, the tag will first be checked to see if it is a data variable, and then execute it as a callback.
  175. {{ template.partial }}
  176. ### The Callback
  177. The callback can be any valid PHP callable. It is sent to the `parse()` method as the third parameter:
  178. $parser->parse(file_get_contents('template.lex'), $data, 'my_callback');
  179. The callback must accept the 3 parameters below (in this order):
  180. $name - The name of the callback tag (it would be "template.partial" in the above examples)
  181. $attributes - An associative array of the attributes set
  182. $content - If it the tag is a block tag, it will be the content contained, else a blank string
  183. The callback must also return a string, which will replace the tag in the content.
  184. **Example**
  185. function my_callback($name, $attributes, $content)
  186. {
  187. // Do something useful
  188. return $result;
  189. }
  190. Recursive Callback Blocks
  191. -------------
  192. The recursive callback tag allows you to loop through a child's element with the same output as the main block. It is triggered
  193. by using the ***recursive*** keyword along with the array key name. The two words must be surrounded by asterisks as shown in the example below.
  194. **Example**
  195. function my_callback($name, $attributes, $content)
  196. {
  197. $data = array(
  198. 'url' => 'url_1',
  199. 'title' => 'First Title',
  200. 'children' => array(
  201. array(
  202. 'url' => 'url_2',
  203. 'title' => 'Second Title',
  204. 'children' => array(
  205. array(
  206. 'url' => 'url_3',
  207. 'title' => 'Third Title'
  208. )
  209. )
  210. ),
  211. array(
  212. 'url' => 'url_4',
  213. 'title' => 'Fourth Title',
  214. 'children' => array(
  215. array(
  216. 'url' => 'url_5',
  217. 'title' => 'Fifth Title'
  218. )
  219. )
  220. )
  221. )
  222. );
  223. $parser = new Lex_Parser();
  224. return $parser->parse($content, $data);
  225. }
  226. In the template set it up as shown below. If `children` is not empty Lex will
  227. parse the contents between the `{{ navigation }}` tags again for each of `children`'s arrays.
  228. The resulting text will then be inserted in place of `{{ *recursive children* }}`. This can be done many levels deep.
  229. <ul>
  230. {{ navigation }}
  231. <li><a href="{{ url }}">{{ title }}</a>
  232. {{ if children }}
  233. <ul>
  234. {{ *recursive children* }}
  235. </ul>
  236. {{ endif }}
  237. </li>
  238. {{ /navigation }}
  239. </ul>
  240. **Result**
  241. <ul>
  242. <li><a href="url_1">First Title</a>
  243. <ul>
  244. <li><a href="url_2">Second Title</a>
  245. <ul>
  246. <li><a href="url_3">Third Title</a></li>
  247. </ul>
  248. </li>
  249. <li><a href="url_4">Fourth Title</a>
  250. <ul>
  251. <li><a href="url_5">Fifth Title</a></li>
  252. </ul>
  253. </li>
  254. </ul>
  255. </li>
  256. </ul>