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

/atk4/lib/ApiWeb.php

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