PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/app/plugins/wildflower/wildflower_app_controller.php

https://github.com/MrRio/wildflower
PHP | 522 lines | 333 code | 67 blank | 122 comment | 42 complexity | 64cf34d9f16ecb08f21155a3b29becd8 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. uses('Sanitize');
  3. App::import('Core', 'l10n');
  4. class WildflowerAppController extends AppController {
  5. public $components = array('Auth', 'Cookie', 'RequestHandler', 'Wildflower.Seo');
  6. public $currentUserId;
  7. public $helpers = array('Html', 'Wildflower.Htmla', 'Form', 'Javascript', 'Wildflower.Wild', 'Wildflower.Navigation', 'Wildflower.PartialLayout');
  8. public $homePageId;
  9. public $isAuthorized = false;
  10. public $isHome = false;
  11. public $view = 'Theme';
  12. public $theme = 'wildflower';
  13. private $_isDatabaseConnected = true;
  14. function __construct() {
  15. // Autoload APP helpers
  16. $appHelpers = scandir(APP . 'views' . DS . 'helpers');
  17. foreach ($appHelpers as $i => $fileName) {
  18. if ($fileName[0] == '.' or strpos($fileName, '.php') < 1) {
  19. unset($appHelpers[$i]);
  20. continue;
  21. }
  22. $fileName = str_replace('.php', '', $fileName);
  23. $appHelpers[$i] = Inflector::camelize($fileName);
  24. }
  25. $this->helpers = am($this->helpers, $appHelpers);
  26. parent::__construct();
  27. }
  28. /**
  29. * Called before any controller action
  30. *
  31. * Do 3 things:
  32. * 1. protect admin area
  33. * 2. check for user sessions
  34. * 3. set site parameters
  35. */
  36. function beforeFilter() {
  37. parent::beforeFilter();
  38. // Wilflower callbacks from app/controllers/wildflower_callbacks
  39. $this->wildflowerCallback('before');
  40. // AuthComponent settings
  41. $this->Auth->userModel = 'WildUser';
  42. $this->Auth->fields = array('username' => 'login', 'password' => 'password');
  43. $prefix = Configure::read('Wildflower.prefix');
  44. $this->Auth->loginAction = "/$prefix/login";
  45. $this->Auth->logoutAction = array('plugin' => 'wildflower', 'prefix' => $prefix, 'controller' => 'wild_users', 'action' => 'logout');
  46. $this->Auth->autoRedirect = false;
  47. $this->Auth->allow('update_root_cache'); // requestAction() actions need to be allowed
  48. $this->Auth->loginRedirect = "/$prefix";
  49. $this->_assertDatabaseConnection();
  50. $this->_configureSite();
  51. // Admin area requires authentification
  52. if ($this->isAdminAction()) {
  53. // Set admin layout and admin specific view vars
  54. $this->layout = 'admin_default';
  55. } else {
  56. $this->layout = 'default';
  57. $this->Auth->allow('*');
  58. }
  59. $this->isAuthorized = $this->Auth->isAuthorized();
  60. // Internationalization
  61. $this->L10n = new L10n();
  62. $this->L10n->get('eng');
  63. Configure::write('Config.language', 'en');
  64. // Site settings
  65. $this->_siteSettings = Configure::read('AppSettings');
  66. // Home page ID
  67. $this->homePageId = intval(Configure::read('AppSettings.home_page_id'));
  68. // Set cookie defaults
  69. $this->cookieName = Configure::read('Wildflower.cookie.name');
  70. $this->cookieTime = Configure::read('Wildflower.cookie.expire');
  71. $this->cookieDomain = '.' . getenv('SERVER_NAME');
  72. // Compress output to save bandwith / speed site up
  73. if (!isset($this->params['requested']) && Configure::read('Wildflower.gzipOutput')) {
  74. $this->gzipOutput();
  75. }
  76. }
  77. /**
  78. * @TODO legacy code, refacor
  79. *
  80. * Delete an item
  81. *
  82. * @param int $id
  83. */
  84. function wf_delete($id = null) {
  85. $id = intval($id);
  86. $model = $this->modelClass;
  87. if ($this->RequestHandler->isAjax()) {
  88. $success = $this->{$model}->del($id);
  89. $responce = json_encode(array('success' => $success, 'id' => $id));
  90. header('Content-type: text/plain');
  91. exit($responce);
  92. }
  93. if (empty($this->data)) {
  94. $this->data = $this->{$model}->findById($id);
  95. if (empty($this->data)) {
  96. $this->indexRedirect();
  97. }
  98. } else {
  99. if ($this->{$model}->del($this->data[$model][$this->{$model}->primaryKey])) {
  100. $this->Session->setFlash("{$model} #$id was deleted.");
  101. $this->redirect(array('action' => 'index'));
  102. } else {
  103. $this->Session->setFlash("Error while deleting {$model} #$id.");
  104. }
  105. }
  106. }
  107. /**
  108. * Update more records at once
  109. *
  110. * @TODO Could be much faster using custom UPDATE or DELETE queries
  111. */
  112. function wf_mass_update() {
  113. if (isset($this->data['__action'])) {
  114. foreach ($this->data['id'] as $id => $checked) {
  115. if (intval($checked) === 1) {
  116. switch ($this->data['__action']) {
  117. case 'delete':
  118. // Delete with comments
  119. $this->{$this->modelClass}->delete($id);
  120. break;
  121. case 'publish':
  122. $this->{$this->modelClass}->publish($id);
  123. break;
  124. case 'draft':
  125. $this->{$this->modelClass}->draft($id);
  126. break;
  127. }
  128. }
  129. }
  130. }
  131. $link = am($this->params['named'], array('action' => 'wf_index'));
  132. return $this->redirect($link);
  133. }
  134. /**
  135. * Admin search
  136. *
  137. * @param string $query Search term, encoded by Javascript's encodeURI()
  138. */
  139. function wf_search($query = '') {
  140. $query = urldecode($query);
  141. $results = $this->{$this->modelClass}->search($query);
  142. $this->set('results', $results);
  143. $this->render('/wild_dashboards/wf_search');
  144. }
  145. /**
  146. * Preview a post or a page
  147. *
  148. * @param string $fileName Cached page/post content file name
  149. */
  150. function wf_preview($fileName = null) {
  151. if (is_null($fileName)) return $this->cakeError('object_not_found');
  152. $this->layout = 'default';
  153. $previewData = $this->__readPreviewCache($fileName);
  154. $id = intval($previewData[$this->modelClass]['id']);
  155. $item = $this->{$this->modelClass}->findById($id);
  156. if (empty($item)) $this->cakeError('object_not_found');
  157. if (is_array($previewData) && !empty($previewData)) {
  158. unset($previewData[$this->modelClass]['created']);
  159. $item[$this->modelClass] = am($item[$this->modelClass], $previewData[$this->modelClass]);
  160. }
  161. $itemName = 'item';
  162. switch ($this->modelClass) {
  163. case 'WildPost':
  164. $itemName = 'post';
  165. break;
  166. case 'WildPage':
  167. $itemName = 'page';
  168. break;
  169. }
  170. $params = array($itemName => $item);
  171. if (isset($item[$this->modelClass]['description_meta_tag'])) {
  172. $params['descriptionMetaTag'] = $item[$this->modelClass]['description_meta_tag'];
  173. }
  174. $this->set($params);
  175. $this->pageTitle = $item[$this->modelClass]['title'];
  176. if ($this->modelClass = 'WildPost') {
  177. return $this->render('view');
  178. } else if ($this->modelClass = 'WildPage') {
  179. return $this->_chooseTemplate($item[$this->modelClass]['slug']);
  180. }
  181. }
  182. /**
  183. * Make sure the application returns 404 if it's not a requested action
  184. *
  185. */
  186. function assertInternalRequest() {
  187. $this->autoRender = false;
  188. if ($this->params['requested']) {
  189. return true;
  190. }
  191. $this->do404();
  192. return false;
  193. }
  194. function xssBlackHole() {
  195. $this->cakeError('xss');
  196. }
  197. function afterFilter() {
  198. parent::afterFilter();
  199. $this->wildflowerCallback();
  200. }
  201. /**
  202. * Launch callbacks if they exist for current controller/method
  203. *
  204. * Callback for controllers are stored in <code>app/controllers/wildflower-callbacks/</code>.
  205. * The name convencions is unserscored class that you want to plug into with "_callback"
  206. * suffix. Examples:
  207. *
  208. * - wild_pages_controller_callback.php
  209. * - wild_comments_controller_callback.php
  210. * - wildflower_app_controller_callback.php
  211. *
  212. * @param string $when Launch <code>before</code> or <code>after</code> current action
  213. */
  214. function wildflowerCallback($when = 'after') {
  215. // app_controller
  216. if (class_exists('WildflowerAppControllerCallback')) {
  217. $plugin = new WildflowerAppControllerCallback;
  218. foreach (array('beforeFilter', 'afterFilter') as $filter) {
  219. $method = $filter;
  220. if (method_exists($plugin, $method)) {
  221. $plugin->{$method}();
  222. return;
  223. }
  224. }
  225. }
  226. $className = Inflector::camelize($this->params['controller']) . 'ControllerCallback';
  227. if (class_exists($className)) {
  228. $plugin = new $className;
  229. $method = $when . '_' . $this->params['action'];
  230. if (method_exists($plugin, $method)) {
  231. $plugin->{$method}();
  232. return;
  233. }
  234. }
  235. }
  236. /**
  237. * Before rendering
  238. *
  239. * Set nice SEO titles.
  240. */
  241. function beforeRender() {
  242. parent::beforeRender();
  243. // @TODO: Hmmmm?
  244. if (!$this->_isDatabaseConnected) {
  245. return;
  246. }
  247. $this->Seo->title();
  248. /** @var $refeter string Convenient $referer var in all views **/
  249. $this->set('referer', $this->referer());
  250. // Set view parameters (CmsHelper uses some of these for example)
  251. $params = array(
  252. 'siteName' => Configure::read('AppSettings.site_name'),
  253. 'siteDescription' => Configure::read('AppSettings.description'),
  254. 'isLogged' => $this->isAuthorized,
  255. 'isAuthorized' => $this->isAuthorized,
  256. 'isPage' => false,
  257. 'isPosts' => false,
  258. 'isHome' => $this->isHome,
  259. 'homePageId' => $this->homePageId,
  260. 'here' => substr($this->here, strlen($this->base) - strlen($this->here)),
  261. );
  262. $this->params['Wildflower']['view'] = $params;
  263. $this->set($params);
  264. // User ID for views
  265. $this->set('loggedUserId', $this->Auth->user('id'));
  266. }
  267. function do404() {
  268. $this->pageTitle = 'Page not found';
  269. $this->cakeError('error404', array(array(
  270. 'message' => 'Requested page was not found.',
  271. 'base' => $this->base)));
  272. }
  273. function getLoggedInUserId() {
  274. return $this->Auth->user('id');
  275. }
  276. function wf_create_preview() {
  277. $cacheDir = Configure::read('Wildflower.previewCache');
  278. // Create a unique file name
  279. $fileName = time();
  280. $path = $cacheDir . $fileName . '.json';
  281. while (file_exists($path)) {
  282. $fileName++;
  283. $path = $cacheDir . $fileName . '.json';
  284. }
  285. // Write data to preview file
  286. $data = json_encode($this->data[$this->modelClass]);
  287. file_put_contents($path, $data);
  288. // Garbage collector
  289. $this->__previewCacheGC($cacheDir);
  290. $responce = array('previewFileName' => $fileName);
  291. $this->set('data', $responce);
  292. $this->render('/elements/json');
  293. }
  294. /**
  295. * Tell wheather the current action should be protected
  296. *
  297. * @return bool
  298. */
  299. function isAdminAction() {
  300. $adminRoute = Configure::read('Routing.admin');
  301. $wfPrefix = Configure::read('Wildflower.prefix');
  302. if (isset($this->params[$adminRoute]) && $this->params[$adminRoute] === $wfPrefix) return true;
  303. return (isset($this->params['prefix']) && $this->params['prefix'] === $wfPrefix);
  304. }
  305. /**
  306. * Write all site settings to Configure class as key => value pairs.
  307. * Access them anywhere in the application with Configure::read().
  308. *
  309. */
  310. private function _configureSite() {
  311. $settings = ClassRegistry::init('Wildflower.WildSetting')->getKeyValuePairs();
  312. Configure::write('AppSettings', $settings); // @TODO add under Wildlfower. configure namespace
  313. Configure::write('Wildflower.settings', $settings); // The new namespace for WF settings
  314. }
  315. /**
  316. * Delete old files from preview cache
  317. *
  318. * @link http://www.jonasjohn.de/snippets/php/delete-temporary-files.htm
  319. *
  320. * @param string $path
  321. */
  322. protected function __previewCacheGC($path) {
  323. // Filetypes to check (you can also use *.*)
  324. $fileTypes = '*.json';
  325. // Here you can define after how many
  326. // minutes the files should get deleted
  327. $expire_time = 120;
  328. // Find all files of the given file type
  329. foreach (glob($path . $fileTypes) as $Filename) {
  330. // Read file creation time
  331. $FileCreationTime = filectime($Filename);
  332. // Calculate file age in seconds
  333. $FileAge = time() - $FileCreationTime;
  334. // Is the file older than the given time span?
  335. if ($FileAge > ($expire_time * 60)) {
  336. unlink($Filename);
  337. }
  338. }
  339. }
  340. /**
  341. * Read and decode data from preview cache
  342. *
  343. * @param string $fileName
  344. * @return array
  345. */
  346. protected function __readPreviewCache($fileName) {
  347. $previewCachePath = Configure::read('Wildflower.previewCache') . $fileName . '.json';
  348. if (!file_exists($previewCachePath)) {
  349. return trigger_error("Cache file $previewCachePath does not exist!");
  350. }
  351. $json = file_get_contents($previewCachePath);
  352. $item[$this->modelClass] = json_decode($json, true);
  353. return $item;
  354. }
  355. /**
  356. * Gzip output
  357. *
  358. * Cuts the bandwith cost down to half.
  359. * Helps the responce time.
  360. */
  361. function gzipOutput() {
  362. if (@ob_start('ob_gzhandler')) {
  363. header('Content-type: text/html; charset: UTF-8');
  364. header('Cache-Control: must-revalidate');
  365. $offset = -1;
  366. $expireTime = gmdate('D, d M Y H:i:s', time() + $offset);
  367. $expireHeader = "Expires: $expireTime GMT";
  368. header($expireHeader);
  369. }
  370. }
  371. /**
  372. * Test if we have the connection to the database
  373. *
  374. * @return bool
  375. */
  376. private function _assertDatabaseConnection() {
  377. if (Configure::read('debug') < 1) {
  378. return true;
  379. }
  380. $db = @ConnectionManager::getDataSource('default');
  381. if ($db->connected) {
  382. return true;
  383. }
  384. $this->_isDatabaseConnected = false;
  385. $this->set('database_config', $db->config);
  386. $this->render('/errors/no_database', 'no_database');
  387. exit();
  388. }
  389. /**
  390. * @TODO duplicate in WildflowerAppHelper
  391. * Returns a string with all spaces converted to $replacement and non word characters removed.
  392. *
  393. * @param string $string
  394. * @param string $replacement
  395. * @return string
  396. * @static
  397. */
  398. static function slug($string, $replacement = '-') {
  399. $string = trim($string);
  400. $map = array(
  401. '/à|á|å|â|ä/' => 'a',
  402. '/è|é|ê|ẽ|ë/' => 'e',
  403. '/ì|í|î/' => 'i',
  404. '/ò|ó|ô|ø/' => 'o',
  405. '/ù|ú|ů|û/' => 'u',
  406. '/ç|č/' => 'c',
  407. '/ñ|ň/' => 'n',
  408. '/ľ/' => 'l',
  409. '/ý/' => 'y',
  410. '/ť/' => 't',
  411. '/ž/' => 'z',
  412. '/š/' => 's',
  413. '/æ/' => 'ae',
  414. '/ö/' => 'oe',
  415. '/ü/' => 'ue',
  416. '/Ä/' => 'Ae',
  417. '/Ü/' => 'Ue',
  418. '/Ö/' => 'Oe',
  419. '/ß/' => 'ss',
  420. '/[^\w\s]/' => ' ',
  421. '/\\s+/' => $replacement,
  422. String::insert('/^[:replacement]+|[:replacement]+$/',
  423. array('replacement' => preg_quote($replacement, '/'))) => '',
  424. );
  425. $string = preg_replace(array_keys($map), array_values($map), $string);
  426. return low($string);
  427. }
  428. function wf_get_fields() {
  429. if (Configure::read('debug') < 1) {
  430. return;
  431. }
  432. $output = '';
  433. foreach ($this->{$this->modelClass}->schema() as $name => $column) {
  434. $output .= "'$name' => array(";
  435. // Fields
  436. foreach ($column as $field => $value) {
  437. if (is_null($value) or $value === '') {
  438. continue;
  439. }
  440. $output .= "'$field' => ";
  441. $value = str_replace("'", "\'", $value);
  442. if (!is_numeric($value)) {
  443. $value = "'$value'";
  444. }
  445. $output .= $value . ', ';
  446. }
  447. $output .= "),\n";
  448. }
  449. pr($output);
  450. die();
  451. }
  452. }