PageRenderTime 37ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Nano/library/Nano/Template.php

http://mvh-source.googlecode.com/
PHP | 287 lines | 189 code | 23 blank | 75 comment | 12 complexity | b2a54ce860e9e881408e91719502c3db MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * Nano's Simple Template Engine. The template class provides two things:
  4. *
  5. * 1) an inheritance based template engine based on similar concepts as Django's
  6. * templating engine from the python world
  7. * 2) an execution scope for templates; variables within the template can be accessed
  8. * as members of this class, and helper classes can be accessed as methods of this class
  9. */
  10. if( ! defined( 'APPLICATION_ROOT' ) ){
  11. $nano_root = dirname( __FILE__ );
  12. define( 'APPLICATION_ROOT', dirname($nano_root) );
  13. }
  14. class Nano_Template{
  15. protected $_parents = array();
  16. protected $_blocks = array();
  17. protected $_helpers = array();
  18. protected $_values = array();
  19. protected $_templatePath = '';
  20. protected $_helperPath = array('helper');
  21. private $_templates = array();
  22. /**
  23. * Class constructor.
  24. * Reuqest object is not optional; other configuration parameters may be
  25. * given as initialization arguments.
  26. *
  27. * @param Nano_Reuqest $request A nano request object
  28. * @param array $config A key/value array
  29. */
  30. public function __construct( array $config = array() ){
  31. foreach( $config as $key => $value ){
  32. $this->__set( $key, $value );
  33. }
  34. }
  35. /**
  36. * Any values you need to carry over to the template are proxied trough
  37. * magical __set and __get
  38. */
  39. public function __set( $key, $value ){
  40. if( ($method = 'set' . ucfirst($key) ) && method_exists( $this, $method ) ){
  41. $this->$method( $value );
  42. }
  43. else if( ($member = "_$key") && property_exists( $this, $member ) ){
  44. $this->$member = $value;
  45. }
  46. else{
  47. $this->_values[$key] = $value;
  48. }
  49. }
  50. /**
  51. * Any values you need to carry over to the template are proxied trough
  52. * magical __set and __get
  53. */
  54. public function __get( $key ){
  55. if( ($member = "_$key") && property_exists( $this, $member ) ){
  56. return $this->$member;
  57. }
  58. else if( key_exists( $key, $this->_values ) ){
  59. return $this->_values[$key];
  60. }
  61. }
  62. /**
  63. * The template class acts as a proxy for helper classes. A helper class may
  64. * be factored by calling it's short name as a method of the current template
  65. * class. The template class then takes care of loading and instantiating
  66. * the helper.
  67. *
  68. * @param string $name Helper name, like 'url' for the url helper
  69. * @param mixed $arguments Optional creation arguments for url helpers
  70. *
  71. * @return void
  72. */
  73. public function __call( $name, $arguments ){
  74. $helper = $this->getHelper( $name );
  75. return call_user_func_array( array($helper, $name), $arguments );
  76. }
  77. public function __toString(){
  78. return $this->toString();
  79. }
  80. public function toString(){
  81. $collect = '';
  82. foreach( $this->_templates as $template ){
  83. $this->_parents = array( $template );
  84. while( count( $this->_parents ) > 0 ){
  85. $tpl = array_pop( $this->_parents );
  86. $path = $this->expandPath( $tpl );
  87. @ob_start();
  88. include( $path );
  89. $content = @ob_get_clean();
  90. }
  91. $collect .= $content;
  92. }
  93. return $collect;
  94. }
  95. /**
  96. * Renders the template; also cascades up to the templates
  97. * this template may inherit from. Template names may be in the form of
  98. * :modulename/:templatepath/:actionpath/:templatename, but without any
  99. * file suffix and relative to the project directory
  100. *
  101. * @param $name Simple template name
  102. * @return string $rendered_output Rendered output
  103. */
  104. public function render( $name ){
  105. $this->_templates[] = $name;
  106. return $this;
  107. }
  108. /**
  109. * Demarcates the start of a named content block in a template.
  110. * Note that only the top parent template can render content outside
  111. * of block regions.
  112. *
  113. * @param string $name Name of the content region, such as "title", "navbar"
  114. */
  115. public function block( $name ){
  116. ob_start();
  117. if( ! key_exists( $name, $this->_blocks ) ){
  118. $this->_blocks[$name] = array();
  119. }
  120. }
  121. /**
  122. * Announces the end of a named content block, adds the accumulated buffer
  123. * to the _blocks array and flushes buffer.
  124. *
  125. * N.B. you must properly close each content region.
  126. * N.B. This function produces output, altough during render output is buffered
  127. *
  128. * @param string $name Name of the content region
  129. * @param bool $append=True Should content be inserted at the start or appended
  130. * @return void
  131. */
  132. public function endBlock( $name, $append=True ){
  133. $content = ob_get_clean();
  134. if( $append ){
  135. array_unshift( $this->_blocks[$name], $content );
  136. }
  137. else{
  138. $this->_blocks[$name][] = $content;
  139. }
  140. $string = join( "\n", array_reverse($this->_blocks[$name]) );
  141. echo $string;
  142. }
  143. /**
  144. * Adds a parent template to the list of templates that must be rendered
  145. * @param string $name Relative template name. full path and suffix are added
  146. */
  147. public function inherit( $name ){
  148. $this->_parents[] = $name;
  149. }
  150. /**
  151. * Expands a template name into a template path; e.g. call templates by
  152. * using a relative path starting at the application root.
  153. *
  154. * @param string $name Basic name, like 'edit'. Omit file suffix. Nested names can be page/edit
  155. * @return string $path Full path to /APPLICATION/$name.phtml
  156. */
  157. private function expandPath( $name ){
  158. $name = trim( $name, ' /\\');
  159. //$path = array(trim( $this->_templatePath, ' /\\'), );
  160. //$path = join( '/', array_filter($path));
  161. //return APPLICATION_PATH . '/' . $path;
  162. $path = join( '/', array_filter( array(
  163. APPLICATION_ROOT,
  164. trim( $this->_templatePath, ' /\\'),
  165. $name . '.phtml'
  166. )));
  167. return $path;
  168. }
  169. /**
  170. * Wrapper around the script helper
  171. */
  172. public function headScript(){
  173. return $this->getHelper( 'Script' );
  174. }
  175. /**
  176. * Retrieves a helper class based on the single name for that helper
  177. *
  178. * @param string $name Plain name; e.g. Nano_Helper_Script becomes 'script'
  179. * @return Nano_Helper $helper
  180. */
  181. public function getHelper( $name ){
  182. if( ! key_exists(strtolower($name) ,$this->_helpers) ){
  183. $this->loadHelper( $name );
  184. }
  185. return $this->_helpers[strtolower($name)];
  186. }
  187. /**
  188. * Performs a lookup, and instantiates a helper class with the simple name $name.
  189. * e.g. 'script' will be expanded to match either 'Helper_Script' or even 'Nano_View_Helper'
  190. *
  191. * Classes that can be accessed trough $_helperPath will get precedence over
  192. * classes from Nano_View_Helper_*
  193. *
  194. * @param string $name Simple helper name, e.g. like 'url'
  195. * @return void
  196. */
  197. public function loadHelper( $name ){
  198. $name = ucfirst( $name );
  199. $klass = "Helper_" . $name;
  200. if( ! class_exists( $klass ) ){
  201. $basename = sprintf( "%s.php", $name );
  202. foreach( $this->_helperPath as $path ){
  203. $path = join( '/', array(APPLICATION_ROOT,$path,$basename));
  204. if( file_exists( $path ) ){
  205. require_once( $path );
  206. }
  207. }
  208. }
  209. if( ! class_exists( $klass ) ){
  210. $klass = 'Nano_View_Helper_' . $name;
  211. }
  212. if( class_exists( $klass ) ){
  213. $this->_helpers[strtolower($name)] = new $klass( $this );
  214. }
  215. else{
  216. //debug_print_backtrace();
  217. throw new Exception( "unable to resolve helper $name" );
  218. }
  219. }
  220. /** various getters and setters **/
  221. public function setValues( array $values = array() ){
  222. $this->_values = $values;
  223. }
  224. public function getValues(){
  225. return $this->_values;
  226. }
  227. public function clearValues(){
  228. $this->_values = array();
  229. }
  230. public function addHelperPath( $path ){
  231. $this->_helperPath[] = $path;
  232. }
  233. public function setHelperPath( array $paths = array() ){
  234. $this->_helperPath = $paths;
  235. }
  236. public function setTemplate( $template ){
  237. $this->_templates = (array) $template;
  238. }
  239. public function setTemplates( $templates ){
  240. $this->_templates = (array) $template;
  241. }
  242. //public function getRequest(){
  243. // return $this->_request;
  244. //}
  245. }