PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/atk4/lib/ApiWeb.php

https://github.com/intuititve/lostandfound
PHP | 357 lines | 272 code | 25 blank | 60 comment | 20 complexity | 6aec140449186d587ffec0f9025657f1 MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php // vim:ts=4:sw=4:et:fdm=marker
  2. /**
  3. * ApiWeb extends an api of CommandLine applications with knowlnedge of HTML
  4. * templates, understanding of pages and routing.
  5. *
  6. * @link http://agiletoolkit.org/learn/understand/api
  7. * @link http://agiletoolkit.org/learn/template
  8. *//*
  9. ==ATK4===================================================
  10. This file is part of Agile Toolkit 4
  11. http://agiletoolkit.org/
  12. (c) 2008-2012 Romans Malinovskis <romans@agiletoolkit.org>
  13. Distributed under Affero General Public License v3
  14. See http://agiletoolkit.org/about/license
  15. =====================================================ATK4=*/
  16. class ApiWeb extends ApiCLI {
  17. /** Cleaned up name of the currently requested page */
  18. public $page=null;
  19. /* Root page where URL will send when ('/') is encountered @todo: make this work properly */
  20. public $index_page='index';
  21. /** recorded time when execution has started */
  22. public $start_time=null;
  23. // {{{ Start-up
  24. function __construct($realm=null,$skin='default'){
  25. $this->start_time=time()+microtime();
  26. $this->skin=$skin;
  27. try {
  28. parent::__construct($realm);
  29. }catch (Exception $e){
  30. // This exception is used to abort initialisation of the objects but when
  31. // normal rendering is still required
  32. if($e instanceof Exception_StopInit)return;
  33. $this->caughtException($e);
  34. }
  35. }
  36. /** Redifine this function instead of default constructor */
  37. function init(){
  38. // Do not initialize unless requsetd
  39. //$this->initializeSession();
  40. // find out which page is to display
  41. //$this->calculatePageName();
  42. $this->pm=$this->add('PageManager');
  43. // send headers, no caching
  44. $this->sendHeaders();
  45. $this->cleanMagicQuotes();
  46. parent::init();
  47. /** In addition to default initialization, set up logger and template */
  48. $this->getLogger();
  49. $this->initializeTemplate();
  50. if(get_class($this)=='ApiWeb'){
  51. $this->setConfig(array('url_postfix'=>'.php','url_prefix'=>''));
  52. }
  53. }
  54. /** Magic Quotes were a design error. Let's strip them if they are enabled */
  55. function cleanMagicQuotes(){
  56. function stripslashes_array(&$array, $iterations=0) {
  57. if ($iterations < 3){
  58. foreach ($array as $key => $value){
  59. if (is_array($value)){
  60. stripslashes_array($array[$key], $iterations + 1);
  61. } else {
  62. $array[$key] = stripslashes($array[$key]);
  63. }
  64. }
  65. }
  66. }
  67. if (get_magic_quotes_gpc()){
  68. stripslashes_array($_GET);
  69. stripslashes_array($_POST);
  70. stripslashes_array($_COOKIE);
  71. }
  72. }
  73. /** Sends default headers. Re-define to send your own headers */
  74. function sendHeaders(){
  75. header("Content-Type: text/html; charset=utf-8");
  76. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
  77. header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
  78. header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
  79. header("Cache-Control: post-check=0, pre-check=0", false);
  80. header("Pragma: no-cache"); // HTTP/1.0
  81. }
  82. /** Call this method if you want to see execution time on the bottom of your pages */
  83. function showExecutionTime(){
  84. $self=$this;
  85. $this->addHook('post-render-output',array($this,'_showExecutionTime'));
  86. $this->addHook('post-js-execute',array($this,'_showExecutionTimeJS'));
  87. }
  88. /** @ignore */
  89. function _showExecutionTime(){
  90. echo 'Took '.(time()+microtime()-$this->start_time).'s';
  91. }
  92. /** @ignore */
  93. function _showExecutionTimeJS(){
  94. echo "\n\n/* Took ".number_format(time()+microtime()-$this->start_time,5).'s */';
  95. }
  96. /** If version tag is defined in template, inserts current version of Agile Toolkit there. If newer verison is available, it will be reflected */
  97. function upgradeChecker(){
  98. // Checks for ATK upgrades and shows current version
  99. if($this->template && $this->template->is_set('version')){
  100. $this->add('UpgradeChecker',null,'version');
  101. }
  102. }
  103. // }}}
  104. // {{{ Obsolete
  105. /** @obsolete */
  106. function caughtException($e){
  107. $this->hook('caught-exception',array($e));
  108. echo "<font color=red>",$e,"</font>";
  109. echo "<p>Please use 'Logger' class for more sophisticated output<br>\$api-&gt;add('Logger');</p>";
  110. exit;
  111. }
  112. /** @obsolete */
  113. function outputWarning($msg,$shift=0){
  114. if($this->hook('output-warning',array($msg,$shift)))return true;
  115. echo "<font color=red>",$msg,"</font>";
  116. }
  117. /** @obsolete */
  118. function outputDebug($msg,$shift=0){
  119. if($this->hook('output-debug',array($msg,$shift)))return true;
  120. echo "<font color=red>",$msg,"</font><br>";
  121. }
  122. /** @obsolete */
  123. function outputInfo($msg,$shift=0){
  124. if($this->hook('output-info',array($msg,$shift)))return true;
  125. echo "<font color=red>",$msg,"</font>";
  126. }
  127. // }}}
  128. // {{{ Session Initialization
  129. /** Initializes existing or new session */
  130. public $_is_session_initialized=false;
  131. function initializeSession($create=true){
  132. /* Attempts to re-initialize session. If session is not found,
  133. new one will be created, unless $create is set to false. Avoiding
  134. session creation and placing cookies is to enhance user privacy.
  135. Call to memorize() / recall() will automatically create session */
  136. if($this->_is_session_initialized)return;
  137. if(isset($_GET['SESSION_ID']))session_id($_GET['SESSION_ID']);
  138. // Change settings if defined in settings file
  139. $params=session_get_cookie_params();
  140. $params['httponly']=true; // true by default
  141. foreach($params as $key=>$default){
  142. $params[$key]=$this->api->getConfig('session/'.$key,$default);
  143. }
  144. if($create==false && !isset($_COOKIE[$this->name]))return;
  145. $this->_is_session_initialized=true;
  146. session_set_cookie_params(
  147. $params['lifetime'],
  148. $params['path'],
  149. $params['domain'],
  150. $params['secure'],
  151. $params['httponly']
  152. );
  153. session_name($this->name);
  154. session_start();
  155. }
  156. // }}}
  157. // {{{ Sticky GET Argument implementation. Register stickyGET to have it appended to all generated URLs
  158. public $sticky_get_arguments = array();
  159. /** Make current get argument with specified name automatically appended to all generated URLs */
  160. function stickyGET($name){
  161. $this->sticky_get_arguments[$name]=@$_GET[$name];
  162. }
  163. /** Remove sticky GET which was set by stickyGET */
  164. function stickyForget($name){
  165. unset($this->sticky_get_arguments[$name]);
  166. }
  167. /** @ignore - used by URL class */
  168. function getStickyArguments(){
  169. return $this->sticky_get_arguments;
  170. }
  171. // }}}
  172. // {{{ Very Important Methods
  173. /** Call this method from your index file. It is the main method of Agile Toolkit */
  174. function main(){
  175. try{
  176. // Initialize page and all elements from here
  177. $this->initLayout();
  178. }catch(Exception $e){
  179. if(!($e instanceof Exception_StopInit))
  180. return $this->caughtException($e);
  181. $this->caughtException($e);
  182. }
  183. try{
  184. $this->hook('post-init');
  185. $this->hook('pre-exec');
  186. if(isset($_GET['submit']) && $_POST){
  187. $this->hook('submitted');
  188. }
  189. $this->hook('post-submit');
  190. $this->execute();
  191. }catch(Exception $e){
  192. $this->caughtException($e);
  193. }
  194. }
  195. /** Main execution loop */
  196. function execute(){
  197. $this->rendered['sub-elements']=array();
  198. try {
  199. $this->hook('pre-render');
  200. $this->recursiveRender();
  201. if(isset($_GET['cut_object']))
  202. throw new BaseException("Unable to cut object with name='".$_GET['cut_object']."'. It wasn't initialized");
  203. if(isset($_GET['cut_region'])){
  204. if(!$this->cut_region_result)
  205. throw new BaseException("Unable to cut region with name='".$_GET['cut_region']."'");
  206. echo $this->cut_region_result;
  207. return;
  208. }
  209. }catch(Exception $e){
  210. if($e instanceof Exception_StopRender){
  211. $this->hook('cut-output');
  212. echo $e->result;
  213. $this->hook('post-render-output');
  214. return;
  215. }
  216. throw $e;
  217. }
  218. }
  219. /** Renders all objects inside applications and echo all output to the browser */
  220. function render(){
  221. if(isset($this->api->jquery) && $this->api->jquery)$this->api->jquery->getJS($this);
  222. if(!($this->template)){
  223. throw new BaseException("You should specify template for API object");
  224. }
  225. $this->hook('pre-render-output');
  226. if(headers_sent($file,$line)){
  227. echo "<br/>Direct output (echo or print) detected on $file:$line. <a target='_blank' "
  228. ."href='http://agiletoolkit.org/error/direct_output'>Use \$this->add('Text') instead</a>.<br/>";
  229. }
  230. echo $this->template->render();
  231. $this->hook('post-render-output');
  232. }
  233. // }}}
  234. // {{{ Miscelanious Functions
  235. /** Perform instant redirect to another page */
  236. function redirect($page=null,$args=array()){
  237. /**
  238. * Redirect to specified page. $args are $_GET arguments.
  239. * Use this function instead of issuing header("Location") stuff
  240. */
  241. $url=$this->url($page,$args);
  242. if($this->api->isAjaxOutput())$this->api->js()->univ()->redirect($url)->execute();
  243. header("Location: ".$url);
  244. exit;
  245. }
  246. /** Called on all templates in the system, populates some system-wide tags */
  247. function setTags($t){
  248. // absolute path to base location
  249. $t->trySet('atk_path',$q=
  250. $this->api->pathfinder->atk_location->getURL().'/');
  251. $t->trySet('base_path',$q=$this->api->pm->base_path);
  252. // We are using new capability of SMlite to process tags individually
  253. $t->eachTag('template',array($this,'_locateTemplate'));
  254. $t->eachTag('page',array($this,'_locatePage'));
  255. $this->hook('set-tags',array($t));
  256. }
  257. /** Returns true if browser is going to EVAL output. */
  258. function isAjaxOutput(){
  259. // TODO: rename into isJSOutput();
  260. return isset($_POST['ajax_submit']);
  261. }
  262. /** @private */
  263. function _locateTemplate($path){
  264. return $this->locateURL('template',$path);
  265. }
  266. /** @private */
  267. function _locatePage($path){
  268. return $this->getDestinationURL($path);
  269. }
  270. /** Only show $object in the final rendering */
  271. function renderOnly($object){
  272. $_GET['cut_object']=$object->name;
  273. return $this;
  274. }
  275. // }}}
  276. // {{{ Layout implementation
  277. private $layout_initialized=false;
  278. /** Implements Layouts. Layout is region in shared template which may be replaced by object */
  279. function initLayout(){
  280. if($this->layout_initialized)throw $this->exception('Please do not call initLayout() directly from init()','Obsolete');
  281. $this->layout_initialized=true;
  282. }
  283. /** Register new layout, which, if has method and tag in the template, will be rendered */
  284. function addLayout($name){
  285. if(!$this->template)return;
  286. // TODO: change to functionExists()
  287. if(method_exists($this,$lfunc='layout_'.$name)){
  288. if($this->template->is_set($name)){
  289. $this->$lfunc();
  290. }
  291. }
  292. return $this;
  293. }
  294. /** Default handling of Content page. To be replaced by ApiFrontend */
  295. function layout_Content(){
  296. // This function initializes content. Content is page-dependant
  297. $page=str_replace('/','_',$this->page);
  298. if(method_exists($this,$pagefunc='page_'.$page)){
  299. $p=$this->add('Page',$this->page,'Content');
  300. $this->$pagefunc($p);
  301. }else{
  302. $this->api->locate('page',str_replace('_','/',$this->page).'.php');
  303. $this->add('page_'.$page,$page,'Content');
  304. //throw new BaseException("No such page: ".$this->page);
  305. }
  306. }
  307. /** Default template for the application. Redefine to add your own rules. */
  308. function defaultTemplate(){
  309. return array('shared');
  310. }
  311. // }}}
  312. }