PageRenderTime 85ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/webapp/_lib/controller/class.ThinkUpController.php

https://github.com/dash30/ThinkUp
PHP | 444 lines | 239 code | 27 blank | 178 comment | 43 complexity | c36378c1755be8c1eaf5c358d9af1121 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * ThinkUp/webapp/_lib/controller/class.ThinkUpController.php
  5. *
  6. * Copyright (c) 2009-2011 Gina Trapani
  7. *
  8. * LICENSE:
  9. *
  10. * This file is part of ThinkUp (http://thinkupapp.com).
  11. *
  12. * ThinkUp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
  13. * License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any
  14. * later version.
  15. *
  16. * ThinkUp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  17. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  18. * details.
  19. *
  20. * You should have received a copy of the GNU General Public License along with ThinkUp. If not, see
  21. * <http://www.gnu.org/licenses/>.
  22. *
  23. *
  24. * ThinkUp Controller
  25. *
  26. * The parent class of all ThinkUp webapp controllers.
  27. *
  28. * @license http://www.gnu.org/licenses/gpl.html
  29. * @copyright 2009-2011 Gina Trapani
  30. * @author Gina Trapani <ginatrapani[at]gmail[dot]com>
  31. */
  32. abstract class ThinkUpController {
  33. /**
  34. * @var SmartyThinkUp
  35. */
  36. protected $view_mgr;
  37. /**
  38. * @var string Smarty template filename
  39. */
  40. protected $view_template = null;
  41. /**
  42. *
  43. * @var string cache key separator
  44. */
  45. const KEY_SEPARATOR='-';
  46. /**
  47. *
  48. * @var bool
  49. */
  50. protected $profiler_enabled = false;
  51. /**
  52. *
  53. * @var float
  54. */
  55. private $start_time = 0;
  56. /**
  57. *
  58. * @var araray
  59. */
  60. protected $header_scripts = array ();
  61. /**
  62. *
  63. * @var array
  64. */
  65. protected $json_data = null;
  66. /**
  67. *
  68. * @var str
  69. */
  70. protected $content_type = 'text/html';
  71. /**
  72. * Constructs ThinkUpController
  73. *
  74. * Adds email address of currently logged in ThinkUp user, '' if not logged in, to view
  75. * {$logged_in_user}
  76. * @return ThinkUpController
  77. */
  78. public function __construct($session_started=false) {
  79. if (!$session_started) {
  80. session_start();
  81. }
  82. try {
  83. $config = Config::getInstance();
  84. $this->profiler_enabled = Profiler::isEnabled();
  85. if ( $this->profiler_enabled) {
  86. $this->start_time = microtime(true);
  87. }
  88. $this->view_mgr = new SmartyThinkUp();
  89. $this->app_session = new Session();
  90. if ($this->isLoggedIn()) {
  91. $this->addToView('logged_in_user', $this->getLoggedInUser());
  92. }
  93. if ($this->isAdmin()) {
  94. $this->addToView('user_is_admin', true);
  95. }
  96. $THINKUP_VERSION = $config->getValue('THINKUP_VERSION');
  97. $this->addToView('thinkup_version', $THINKUP_VERSION);
  98. if (SessionCache::isKeySet('selected_instance_network') &&
  99. SessionCache::isKeySet('selected_instance_username')) {
  100. $this->addToView('selected_instance_network', SessionCache::get('selected_instance_network'));
  101. $this->addToView('selected_instance_username', SessionCache::get('selected_instance_username'));
  102. $this->addToView('logo_link', 'index.php?u='. SessionCache::get('selected_instance_username')
  103. .'&n='. urlencode(SessionCache::get('selected_instance_network')));
  104. }
  105. } catch (Exception $e) {
  106. Utils::defineConstants();
  107. $cfg_array = array(
  108. 'site_root_path'=>THINKUP_BASE_URL,
  109. 'source_root_path'=>THINKUP_ROOT_PATH,
  110. 'debug'=>false,
  111. 'app_title'=>"ThinkUp",
  112. 'cache_pages'=>false);
  113. $this->view_mgr = new SmartyThinkUp($cfg_array);
  114. }
  115. }
  116. /**
  117. * Handle request parameters for a particular resource and return view markup.
  118. *
  119. * @return str Markup which renders controller results.
  120. */
  121. abstract public function control();
  122. /**
  123. * Returns whether or not ThinkUp user is logged in
  124. *
  125. * @return bool whether or not user is logged in
  126. */
  127. protected function isLoggedIn() {
  128. return Session::isLoggedIn();
  129. }
  130. /**
  131. * Returns whether or not a logged-in ThinkUp user is an admin
  132. *
  133. * @return bool whether or not logged-in user is an admin
  134. */
  135. protected function isAdmin() {
  136. return Session::isAdmin();
  137. }
  138. /**
  139. * Return email address of logged-in user
  140. *
  141. * @return str email
  142. */
  143. protected function getLoggedInUser() {
  144. return Session::getLoggedInUser();
  145. }
  146. /**
  147. * Returns cache key as a string
  148. *
  149. * Set to public for the sake of tests.
  150. * @return str cache key
  151. */
  152. public function getCacheKeyString() {
  153. $view_cache_key = array();
  154. if ($this->getLoggedInUser()) {
  155. array_push($view_cache_key, $this->getLoggedInuser());
  156. }
  157. $keys = array_keys($_GET);
  158. foreach ($keys as $key) {
  159. array_push($view_cache_key, $_GET[$key]);
  160. }
  161. return $this->view_template.self::KEY_SEPARATOR.(implode($view_cache_key, self::KEY_SEPARATOR));
  162. }
  163. /**
  164. * Generates web page markup
  165. *
  166. * @return str view markup
  167. */
  168. protected function generateView() {
  169. // add header javascript if defined
  170. if( count($this->header_scripts) > 0) {
  171. $this->addToView('header_scripts', $this->header_scripts);
  172. }
  173. if (isset($this->view_template)) {
  174. if ($this->view_mgr->isViewCached()) {
  175. $cache_key = $this->getCacheKeyString();
  176. if ($this->profiler_enabled && !isset($this->json_data) && strpos($this->content_type,
  177. 'text/javascript') === false) {
  178. $view_start_time = microtime(true);
  179. $cache_source = $this->shouldRefreshCache()?"DATABASE":"FILE";
  180. $results = $this->view_mgr->fetch($this->view_template, $cache_key);
  181. $view_end_time = microtime(true);
  182. $total_time = $view_end_time - $view_start_time;
  183. $profiler = Profiler::getInstance();
  184. $profiler->add($total_time, "Rendered view from ". $cache_source . ", cache key: <i>".
  185. $this->getCacheKeyString(), false).'</i>';
  186. return $results;
  187. } else {
  188. return $this->view_mgr->fetch($this->view_template, $cache_key);
  189. }
  190. } else {
  191. if ($this->profiler_enabled && !isset($this->json_data) && strpos($this->content_type,
  192. 'text/javascript') === false) {
  193. $view_start_time = microtime(true);
  194. $results = $this->view_mgr->fetch($this->view_template);
  195. $view_end_time = microtime(true);
  196. $total_time = $view_end_time - $view_start_time;
  197. $profiler = Profiler::getInstance();
  198. $profiler->add($total_time, "Rendered view (not cached)", false);
  199. return $results;
  200. } else {
  201. return $this->view_mgr->fetch($this->view_template);
  202. }
  203. }
  204. } else if(isset($this->json_data) ) {
  205. $this->setContentType('application/json');
  206. return json_encode($this->json_data);
  207. } else {
  208. throw new Exception(get_class($this).': No view template specified');
  209. }
  210. }
  211. /**
  212. * Sets the view template filename
  213. *
  214. * @param str $tpl_filename
  215. */
  216. protected function setViewTemplate($tpl_filename) {
  217. $this->view_template = $tpl_filename;
  218. }
  219. /**
  220. * Sets json data structure to output a json string, and sets Content-Type to appplication/json
  221. *
  222. * @param array json data
  223. */
  224. protected function setJsonData($data) {
  225. $this->json_data = $data;
  226. }
  227. /**
  228. * Sets Content Type header
  229. *
  230. * @param string Content Type
  231. */
  232. protected function setContentType($content_type) {
  233. $this->content_type = $content_type;
  234. // if is to suppress 'headers already sent' error while testing, etc.
  235. if( ! headers_sent() ) {
  236. header('Content-Type: ' . $this->content_type, true);
  237. }
  238. }
  239. /**
  240. * Gets Content Type header
  241. *
  242. * @return string Content Type
  243. */
  244. public function getContentType() {
  245. return $this->content_type;
  246. }
  247. /**
  248. * Add javascript to header
  249. *
  250. * @param str javascript path
  251. */
  252. public function addHeaderJavaScript($script) {
  253. array_push($this->header_scripts, $script);
  254. }
  255. /**
  256. * Add data to view template engine for rendering
  257. *
  258. * @param str $key
  259. * @param mixed $value
  260. */
  261. protected function addToView($key, $value) {
  262. $this->view_mgr->assign($key, $value);
  263. }
  264. /**
  265. * Invoke the controller
  266. *
  267. * Always use this method, not control(), to invoke the controller.
  268. * @TODO show get 500 error template on Exception
  269. * (if debugging is true, pass the exception details to the 500 template)
  270. */
  271. public function go() {
  272. try {
  273. $this->initalizeApp();
  274. // are we in need of a database migration?
  275. $classname = get_class($this);
  276. if ($classname != 'InstallerController' && $classname != 'BackupController' &&
  277. UpgradeController::isUpgrading( $this->isAdmin(), $classname) ) {
  278. $this->setViewTemplate('install.upgradeneeded.tpl');
  279. $this->disableCaching();
  280. $option_dao = DAOFactory::getDAO('OptionDAO');
  281. $option_dao->clearSessionData(OptionDAO::APP_OPTIONS);
  282. return $this->generateView();
  283. } else {
  284. $results = $this->control();
  285. if ($this->profiler_enabled && !isset($this->json_data)
  286. && strpos($this->content_type, 'text/javascript') === false
  287. && strpos($this->content_type, 'text/csv') === false) {
  288. $end_time = microtime(true);
  289. $total_time = $end_time - $this->start_time;
  290. $profiler = Profiler::getInstance();
  291. $this->disableCaching();
  292. $profiler->add($total_time,
  293. "total page execution time, running ".$profiler->total_queries." queries.");
  294. $this->setViewTemplate('_profiler.tpl');
  295. $this->addToView('profile_items',$profiler->getProfile());
  296. return $results . $this->generateView();
  297. } else {
  298. return $results;
  299. }
  300. }
  301. } catch (Exception $e) {
  302. //Explicitly set TZ (before we have user's choice) to avoid date() warning about using system settings
  303. date_default_timezone_set('America/Los_Angeles');
  304. $content_type = $this->content_type;
  305. if (strpos($content_type, ';') !== FALSE) {
  306. $content_type = array_shift(explode(';', $content_type));
  307. }
  308. switch ($content_type) {
  309. case 'application/json':
  310. $this->setViewTemplate('500.json.tpl');
  311. break;
  312. case 'text/plain':
  313. $this->setViewTemplate('500.txt.tpl');
  314. break;
  315. default:
  316. $this->setViewTemplate('500.tpl');
  317. }
  318. $this->addToView('error_type', get_class($e));
  319. $this->addErrorMessage($e->getMessage());
  320. return $this->generateView();
  321. }
  322. }
  323. /**
  324. * Initalize app
  325. * Load config file and required plugins
  326. * @throws Exception
  327. */
  328. private function initalizeApp() {
  329. $classname = get_class($this);
  330. if ($classname != "InstallerController") {
  331. //Initialize config
  332. $config = Config::getInstance();
  333. if ($config->getValue('timezone')) {
  334. date_default_timezone_set($config->getValue('timezone'));
  335. }
  336. if ($config->getValue('debug')) {
  337. ini_set("display_errors", 1);
  338. ini_set("error_reporting", E_ALL);
  339. }
  340. if($classname != "BackupController") {
  341. //Init plugins
  342. $pdao = DAOFactory::getDAO('PluginDAO');
  343. $active_plugins = $pdao->getActivePlugins();
  344. Utils::defineConstants();
  345. foreach ($active_plugins as $ap) {
  346. //add plugin's model and controller folders as Loader paths here
  347. Loader::addPath(THINKUP_WEBAPP_PATH.'plugins/'.$ap->folder_name."/model/");
  348. Loader::addPath(THINKUP_WEBAPP_PATH.'plugins/'.$ap->folder_name.
  349. "/controller/");
  350. //require the main plugin registration file here
  351. if ( file_exists(
  352. THINKUP_WEBAPP_PATH.'plugins/'.$ap->folder_name."/controller/".$ap->folder_name.".php")) {
  353. require_once THINKUP_WEBAPP_PATH.'plugins/'.$ap->folder_name."/controller/".$ap->folder_name.
  354. ".php";
  355. }
  356. }
  357. }
  358. }
  359. }
  360. /**
  361. * Provided for tests only, to assert that proper view values have been set. (Debug must be equal to true.)
  362. * @return SmartyThinkUp
  363. */
  364. public function getViewManager() {
  365. return $this->view_mgr;
  366. }
  367. /**
  368. * Turn off caching
  369. * Provided in case an individual controller wants to override the application-wide setting.
  370. */
  371. protected function disableCaching() {
  372. $this->view_mgr->disableCaching();
  373. }
  374. /**
  375. * Check if cache needs refreshing
  376. * @return bool
  377. */
  378. protected function shouldRefreshCache() {
  379. if ($this->view_mgr->isViewCached()) {
  380. return !$this->view_mgr->is_cached($this->view_template, $this->getCacheKeyString());
  381. } else {
  382. return true;
  383. }
  384. }
  385. /**
  386. * Set web page title
  387. * This method only works for views that reference _header.tpl.
  388. * @param str $title
  389. */
  390. public function setPageTitle($title) {
  391. $this->addToView('controller_title', $title);
  392. }
  393. /**
  394. * Add error message to view
  395. * @param str $msg
  396. */
  397. public function addErrorMessage($msg) {
  398. $this->disableCaching();
  399. $this->addToView('errormsg', $msg );
  400. }
  401. /**
  402. * Add success message to view
  403. * @param str $msg
  404. */
  405. public function addSuccessMessage($msg) {
  406. $this->disableCaching();
  407. $this->addToView('successmsg', $msg );
  408. }
  409. /**
  410. * Add informational message to view
  411. * @param str $msg
  412. */
  413. public function addInfoMessage($msg) {
  414. $this->disableCaching();
  415. $this->addToView('infomsg', $msg );
  416. }
  417. }