PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/A/Http/View.php

http://skeleton.googlecode.com/
PHP | 499 lines | 377 code | 48 blank | 74 comment | 53 complexity | 4d41cd45b8642f5ebcd91f6dd97a85ea MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * View.php
  4. *
  5. * @license http://www.opensource.org/licenses/bsd-license.php BSD
  6. * @link http://skeletonframework.com/
  7. */
  8. /**
  9. * A_Http_View
  10. *
  11. * Base MVC View class for a whole or partial HTTP response. Encapsulates headers, redirects, character encoding, quoting, escaping, and content.
  12. *
  13. * @package A_Http
  14. */
  15. class A_Http_View implements A_Renderer
  16. {
  17. protected $data = array();
  18. protected $escape_fields = array(); // array of keys in $data to escape, values are true/false whether field is escaped
  19. protected $template = null;
  20. protected $template_type = 'templates';
  21. protected $template_path = 'templates';
  22. protected $template_scope = 'module';
  23. protected $content = ''; // buffer set manually or by render()
  24. protected $renderer = null;
  25. protected $headers = array();
  26. protected $cookies = array();
  27. protected $redirect = null;
  28. protected $escape_quote_style = ENT_QUOTES;
  29. protected $character_set = 'UTF-8';
  30. protected $locator = null;
  31. protected $load;
  32. protected $flash;
  33. protected $mapper_name = 'Mapper'; // name in registry
  34. protected $paths = array(); // cache array of paths calculated by Mapper
  35. protected $helpers = array();
  36. protected $helperClass = array(
  37. 'datetime'=>'A_Datetime',
  38. 'json'=>'A_Json',
  39. 'pagination'=>'A_Pagination_View_Standard',
  40. 'url'=>'A_Http_Helper_Url',
  41. );
  42. protected $use_local_vars = true;
  43. protected $errorMsg = array();
  44. public function __construct($locator=null)
  45. {
  46. $this->locator = $locator;
  47. }
  48. public function setLocator($locator)
  49. {
  50. $this->locator = $locator;
  51. }
  52. public function setCharacterSet($character_set)
  53. {
  54. $this->character_set = $character_set;
  55. return $this;
  56. }
  57. public function setQuoteStyle($escape_quote_style)
  58. {
  59. $this->escape_quote_style = $escape_quote_style;
  60. return $this;
  61. }
  62. public function useLocalVars($use_local_vars)
  63. {
  64. $this->use_local_vars = $use_local_vars;
  65. return $this;
  66. }
  67. public function setHeader($field, $param=null)
  68. {
  69. if (is_string($field)) {
  70. if (is_array($param)) {
  71. $this->headers[$field] = $param;
  72. } elseif ($param === null) {
  73. unset($this->headers[$field]);
  74. } else {
  75. $this->headers[$field] = array(0 => $param);
  76. }
  77. }
  78. return $this;
  79. }
  80. public function getHeaders()
  81. {
  82. return $this->headers;
  83. }
  84. /**
  85. * @param Parameters the same as the PHP setcookie() function
  86. */
  87. public function setCookie()
  88. {
  89. $args = func_get_args();
  90. if ($args) {
  91. $this->cookies[$args[0]] = $args;
  92. }
  93. return $this;
  94. }
  95. public function getCookie($name)
  96. {
  97. if (isset($this->cookies[$name])) {
  98. return $this->cookies[$name];
  99. }
  100. }
  101. public function setRedirect($url)
  102. {
  103. $this->redirect = $url;
  104. return $this;
  105. }
  106. public function getRedirect()
  107. {
  108. return $this->redirect;
  109. }
  110. public function setContent($content)
  111. {
  112. $this->content = $content;
  113. return $this;
  114. }
  115. public function getContent()
  116. {
  117. return $this->content;
  118. }
  119. public function setTemplate($template, $scope='')
  120. {
  121. $this->template = $template;
  122. if ($scope) $this->template_scope = $scope;
  123. return $this;
  124. }
  125. public function setTemplateScope($scope)
  126. {
  127. $this->template_scope = $scope;
  128. return $this;
  129. }
  130. public function setTemplatePath($path)
  131. {
  132. $this->template_path = $path;
  133. return $this;
  134. }
  135. public function getTemplate()
  136. {
  137. return $this->template;
  138. }
  139. public function setRenderer($renderer)
  140. {
  141. $this->renderer = $renderer;
  142. return $this;
  143. }
  144. public function hasRenderer()
  145. {
  146. return isset($this->renderer);
  147. }
  148. public function set($name, $value, $default=null)
  149. {
  150. if ($value !== null) {
  151. $this->data[$name] = $value;
  152. if (isset($this->escape_fields[$name])) {
  153. $this->escape_fields[$name] = false;
  154. }
  155. } elseif ($default !== null) {
  156. $this->data[$name] = $default;
  157. if (isset($this->escape_fields[$name])) {
  158. $this->escape_fields[$name] = false;
  159. }
  160. } else {
  161. unset($this->data[$name]);
  162. unset($this->escape_fields[$name]);
  163. }
  164. return $this;
  165. }
  166. public function get($name)
  167. {
  168. return isset($this->data[$name]) ? $this->data[$name] : null;
  169. }
  170. public function has($name)
  171. {
  172. return isset($this->data[$name]);
  173. }
  174. public function import($data)
  175. {
  176. $this->data = array_merge($this->data, $data);
  177. return $this;
  178. }
  179. public function escape($content, $escape_quote_style=null)
  180. {
  181. if (extension_loaded('mbstring')) {
  182. mb_substitute_character('none');
  183. $content = mb_convert_encoding($content, $this->character_set, $this->character_set);
  184. }
  185. return htmlspecialchars($content, $escape_quote_style==null ? $this->escape_quote_style : $escape_quote_style, $this->character_set);
  186. }
  187. public function setEscape($name, $value, $default=null)
  188. {
  189. $this->escape_fields[$name] = false; // Register this to be escaped later. False because not yet escaped.
  190. $this->set($name, $value, $default);
  191. }
  192. /**
  193. * @param $name mixed field name or array of field names to be escaped
  194. */
  195. public function escapeField($names)
  196. {
  197. if (!is_array($names)) {
  198. $names = array($names);
  199. }
  200. foreach ($names as $name) {
  201. if (!isset($this->escape_fields[$name])) { // skip if already registered
  202. $this->escape_fields[$name] = false; // Register this to be escaped later. False because not yet escaped.
  203. }
  204. }
  205. }
  206. /**
  207. *
  208. */
  209. public function _escape()
  210. {
  211. foreach ($this->escape_fields as $field => $isEscaped) {
  212. if (!$isEscaped) {
  213. $this->data[$field] =$this->escape($this->data[$field]);
  214. $this->escape_fields[$field] = true; // set to escaped
  215. }
  216. }
  217. }
  218. /**
  219. *
  220. */
  221. public function _escape_array($data, $escape_fields)
  222. {
  223. foreach ($escape_fields as $field) {
  224. $data[$field] = $this->escape($data[$field]);
  225. }
  226. return $data;
  227. }
  228. public function _getPath($template)
  229. {
  230. if (substr($template, -4, 4) != '.php') {
  231. $template .= '.php';
  232. }
  233. // if Locator set by FC then we can get the Mapper
  234. if (method_exists($this->locator, 'get')) {
  235. $mapper = $this->locator->get($this->mapper_name);
  236. if ($mapper) {
  237. // get paths array if not cached
  238. if (! isset($this->paths[$this->template_type])) {
  239. $this->paths[$this->template_type] = $mapper->getPaths($this->template_type);
  240. }
  241. return $this->paths[$this->template_type][$this->template_scope] . $template;
  242. }
  243. }
  244. return $this->template_path . '/' . $template;
  245. }
  246. /**
  247. * Include PHP template
  248. *
  249. * @param string $template
  250. * @param mixed $data
  251. * @return string
  252. */
  253. public function partial($template, $data=null, $escape_fields=null)
  254. {
  255. $template = $this->_getPath($template);
  256. $str = $this->_include($template, $data, $escape_fields);
  257. return $str;
  258. }
  259. /**
  260. * include PHP template for each value in array
  261. *
  262. * @param string $template
  263. * @param string $name
  264. * @param mixed $data
  265. * @return string
  266. */
  267. public function partialLoop($template, $name, $data=null, $escape_fields=null)
  268. {
  269. $template = $this->_getPath($template);
  270. $str = '';
  271. if ($data) {
  272. // $name and $data set so each element in $data set to $name
  273. foreach ($data as $value) {
  274. $str .= $this->_include($template, array($name=>$value), $escape_fields);
  275. }
  276. } else {
  277. $tmp = array();
  278. // $name but not $data, so $name contains $data. set() to $keys in each element array
  279. foreach ($name as $data) {
  280. $str .= $this->_include($template, $data, $escape_fields);
  281. }
  282. // restore original values
  283. foreach($tmp as $key => $value) {
  284. $this->data[$key] = $value;
  285. }
  286. }
  287. return $str;
  288. }
  289. /**
  290. * Convenience method to more easily set a partial template
  291. *
  292. * @param string $name
  293. * @param string $template
  294. * @param mixed $data
  295. * @return @this
  296. */
  297. public function setPartial($name, $template, $data=null) {
  298. $this->set($name, $this->partial($template, $data));
  299. return $this;
  300. }
  301. /**
  302. * short for $this->set($name, $this->partialLoop($template, $data_name, $data))
  303. */
  304. public function setPartialLoop($name, $template, $data_name, $data=null)
  305. {
  306. $this->set($name, $this->partialLoop($template, $data_name, $data));
  307. return $this;
  308. }
  309. public function render($template='', $scope='')
  310. {
  311. if (!$template && $this->template) {
  312. $template = $this->template;
  313. }
  314. if ($scope) {
  315. $this->template_scope = $scope;
  316. }
  317. if ($template) {
  318. $this->content = $this->_include($this->_getPath($template));
  319. } elseif ($this->renderer) {
  320. if ($this->data) {
  321. foreach ($this->data as $name => $value) {
  322. if (is_object($this->data[$name]) && method_exists($this->data[$name], 'render')) {
  323. $this->renderer->set($name, $this->data[$name]->render());
  324. } else {
  325. $this->renderer->set($name, $value);
  326. }
  327. }
  328. }
  329. if (method_exists($this->renderer, 'render')) {
  330. $this->content = $this->renderer->render();
  331. }
  332. }
  333. return $this->content;
  334. }
  335. /*
  336. * Include a PHP file, passing internal data to it as variables
  337. * Note: no local variables are used in this function to keep the namespace clean for extracted variables
  338. * @param $template - the name of the template file
  339. * @param $data - optional array data for template: keys are field names
  340. * @param $escaped_fields - optional array of field names to escape
  341. */
  342. protected function _include(/* $template, $data=array(), $escaped_fields=array() */)
  343. {
  344. if (func_num_args() > 0) { // must have at least the template path
  345. ob_start();
  346. if ($this->use_local_vars && $this->data) {
  347. $this->_escape();
  348. extract($this->data);
  349. }
  350. if ((func_num_args() > 1) && is_array(func_get_arg(1))) { // array of values passed
  351. if ((func_num_args() > 2) && is_array(func_get_arg(2))) { // array of fields to escaped passed
  352. extract($this->_escape_array(func_get_arg(1), func_get_arg(2)));
  353. } else {
  354. extract(func_get_arg(1));
  355. }
  356. }
  357. include func_get_arg(0);
  358. return ob_get_clean();
  359. }
  360. }
  361. public function __get($name)
  362. {
  363. return isset($this->data[$name]) ? $this->data[$name] : null;
  364. }
  365. public function __set($name, $value)
  366. {
  367. return $this->set($name, $value);
  368. }
  369. /**
  370. * Allow calls directly to the renderer object's methods
  371. */
  372. public function __call($name, $args)
  373. {
  374. if (method_exists($this->renderer, $name)) {
  375. return call_user_func_array(array($this->renderer, $name), $args);
  376. }
  377. // TODO elseif $name is a helper then load it
  378. // else throw an error or exception
  379. }
  380. public function __toString()
  381. {
  382. return $this->render();
  383. }
  384. protected function _load($scope=null)
  385. {
  386. if (isset($this->load)) {
  387. $this->load->load($scope);
  388. } else {
  389. $this->load = new A_Controller_Helper_Load($this->locator, $this, $scope);
  390. }
  391. return $this->load;
  392. }
  393. protected function _flash($name=null, $value=null)
  394. {
  395. if (!isset($this->flash)) {
  396. $this->flash = new A_Controller_Helper_Flash($this->locator);
  397. }
  398. if ($name) {
  399. if ($value) {
  400. $this->flash->set($name, $value);
  401. } else {
  402. return $this->flash->get($name);
  403. }
  404. }
  405. return $this->flash;
  406. }
  407. public function setHelper($name, $helper)
  408. {
  409. if ($name) {
  410. $this->helpers[$name] = $helper;
  411. }
  412. return $this;
  413. }
  414. public function setHelperClass($name, $class)
  415. {
  416. if ($name) {
  417. $this->helperClass[$name] = $class;
  418. }
  419. return $this;
  420. }
  421. protected function helper($name)
  422. {
  423. if (!isset($this->helpers[$name])) {
  424. if (isset($this->helperClass[$name])) {
  425. $class = $this->helperClass[$name];
  426. } else {
  427. $class = $name;
  428. }
  429. $this->helpers[$name] = $this->locator->get('', $class, '', $this->locator);
  430. }
  431. if (isset($this->helpers[$name])) {
  432. return $this->helpers[$name];
  433. }
  434. }
  435. /**
  436. * Get error messages
  437. *
  438. * @param string $separator Separator between errors, set to null for an array
  439. * @return string|array
  440. */
  441. public function getErrorMsg($separator="\n") {
  442. $errormsg = $this->errorMsg;
  443. if ($this->load) {
  444. $errormsg = array_merge($errormsg, $this->_load($scope)->getErrorMsg(''));
  445. }
  446. if ($separator) {
  447. $errormsg = implode($separator, $this->errorMsg);
  448. }
  449. return $errormsg;
  450. }
  451. }