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

/Croogo/Controller/CroogoAppController.php

https://github.com/kareypowell/croogo
PHP | 404 lines | 250 code | 33 blank | 121 comment | 45 complexity | ba5c0ac0108a2126733e69cc75a7b207 MD5 | raw file
  1. <?php
  2. App::uses('Controller', 'Controller');
  3. /**
  4. * Croogo App Controller
  5. *
  6. * @category Croogo.Controller
  7. * @package Croogo.Croogo.Controller
  8. * @version 1.5
  9. * @author Fahad Ibnay Heylaal <contact@fahad19.com>
  10. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  11. * @link http://www.croogo.org
  12. */
  13. class CroogoAppController extends Controller {
  14. /**
  15. * Default Components
  16. *
  17. * @var array
  18. * @access public
  19. */
  20. protected $_defaultComponents = array(
  21. 'Croogo.Croogo',
  22. 'Security',
  23. 'Acl',
  24. 'Auth',
  25. 'Session',
  26. 'RequestHandler',
  27. );
  28. /**
  29. * List of registered Application Components
  30. *
  31. * These components are typically hooked into the application during bootstrap.
  32. * @see Croogo::hookComponent
  33. */
  34. protected $_appComponents = array();
  35. /**
  36. * List of registered API Components
  37. *
  38. * These components are typically hooked into the application during bootstrap.
  39. * @see Croogo::hookApiComponent
  40. */
  41. protected $_apiComponents = array();
  42. /**
  43. * Helpers
  44. *
  45. * @var array
  46. * @access public
  47. */
  48. public $helpers = array(
  49. 'Html',
  50. 'Form',
  51. 'Session',
  52. 'Text',
  53. 'Js',
  54. 'Time',
  55. 'Croogo.Layout',
  56. 'Custom',
  57. );
  58. /**
  59. * Pagination
  60. */
  61. public $paginate = array(
  62. 'limit' => 10,
  63. );
  64. /**
  65. * Cache pagination results
  66. *
  67. * @var boolean
  68. * @access public
  69. */
  70. public $usePaginationCache = true;
  71. /**
  72. * View
  73. *
  74. * @var string
  75. * @access public
  76. */
  77. public $viewClass = 'Theme';
  78. /**
  79. * Theme
  80. *
  81. * @var string
  82. * @access public
  83. */
  84. public $theme;
  85. /**
  86. * Constructor
  87. *
  88. * @access public
  89. */
  90. public function __construct($request = null, $response = null) {
  91. parent::__construct($request, $response);
  92. if ($request) {
  93. $request->addDetector('api', array(
  94. 'callback' => array('CroogoRouter', 'isApiRequest'),
  95. ));
  96. $request->addDetector('whitelisted', array(
  97. 'callback' => array('CroogoRouter', 'isWhitelistedRequest'),
  98. ));
  99. }
  100. $this->getEventManager()->dispatch(new CakeEvent('Controller.afterConstruct', $this));
  101. }
  102. /**
  103. * implementedEvents
  104. */
  105. public function implementedEvents() {
  106. return parent::implementedEvents() + array(
  107. 'Controller.afterConstruct' => 'afterConstruct',
  108. );
  109. }
  110. /**
  111. * afterConstruct
  112. *
  113. * called when Controller::__construct() is complete.
  114. * Override this method to perform class configuration/initialization that
  115. * needs to be performed earlier from Controller::beforeFilter().
  116. *
  117. * You still need to call parent::afterConstruct() method to ensure correct
  118. * behavior.
  119. */
  120. public function afterConstruct() {
  121. Croogo::applyHookProperties('Hook.controller_properties', $this);
  122. $this->_setupComponents();
  123. if (isset($this->request->params['admin'])) {
  124. $this->helpers[] = 'Croogo.Croogo';
  125. if (empty($this->helpers['Html'])) {
  126. $this->helpers['Html'] = array('className' => 'Croogo.CroogoHtml');
  127. }
  128. if (empty($this->helpers['Form'])) {
  129. $this->helpers['Form'] = array('className' => 'Croogo.CroogoForm');
  130. }
  131. if (empty($this->helpers['Paginator'])) {
  132. $this->helpers['Paginator'] = array('className' => 'Croogo.CroogoPaginator');
  133. }
  134. }
  135. }
  136. /**
  137. * Setup the components array
  138. *
  139. * @param void
  140. * @return void
  141. */
  142. protected function _setupComponents() {
  143. if ($this->request && !$this->request->is('api')) {
  144. $this->components = Hash::merge(
  145. $this->_defaultComponents,
  146. $this->_appComponents,
  147. $this->components
  148. );
  149. return;
  150. }
  151. $this->components = Hash::merge(
  152. $this->components,
  153. array('Acl', 'Auth', 'Security', 'Session', 'RequestHandler', 'Acl.AclFilter'),
  154. $this->_apiComponents
  155. );
  156. $apiComponents = array();
  157. $priority = 8;
  158. foreach ($this->_apiComponents as $component => $setting) {
  159. if (is_string($setting)) {
  160. $component = $setting;
  161. $setting = array();
  162. }
  163. $className = $component;
  164. list(, $apiComponent) = pluginSplit($component);
  165. $setting = Hash::merge(compact('className', 'priority'), $setting);
  166. $apiComponents[$apiComponent] = $setting;
  167. }
  168. $this->_apiComponents = $apiComponents;
  169. }
  170. /**
  171. * Allows extending action from component
  172. *
  173. * @throws MissingActionException
  174. */
  175. public function invokeAction(CakeRequest $request) {
  176. try {
  177. return parent::invokeAction($request);
  178. } catch (MissingActionException $e) {
  179. $params = $request->params;
  180. $prefix = isset($params['prefix']) ? $params['prefix'] : '';
  181. $action = str_replace($prefix . '_', '', $params['action']);
  182. foreach ($this->_apiComponents as $component => $setting) {
  183. if (empty($this->{$component})) {
  184. continue;
  185. }
  186. if ($this->{$component}->isValidAction($action)) {
  187. $this->setRequest($request);
  188. return $this->{$component}->{$action}($this);
  189. }
  190. }
  191. throw $e;
  192. }
  193. }
  194. /**
  195. * beforeFilter
  196. *
  197. * @return void
  198. * @throws MissingComponentException
  199. */
  200. public function beforeFilter() {
  201. parent::beforeFilter();
  202. $aclFilterComponent = Configure::read('Site.acl_plugin') . 'Filter';
  203. if (empty($this->{$aclFilterComponent})) {
  204. throw new MissingComponentException(array('class' => $aclFilterComponent));
  205. }
  206. $this->{$aclFilterComponent}->auth();
  207. $this->RequestHandler->setContent('json', array('text/x-json', 'application/json'));
  208. if (!$this->request->is('api')) {
  209. $this->Security->blackHoleCallback = 'securityError';
  210. $this->Security->requirePost('admin_delete');
  211. }
  212. if (isset($this->request->params['admin'])) {
  213. $this->layout = 'admin';
  214. if ($adminTheme = Configure::read('Site.admin_theme')) {
  215. App::build(array(
  216. 'View/Helper' => array(App::themePath($adminTheme) . 'Helper' . DS),
  217. ));
  218. }
  219. }
  220. if ($this->RequestHandler->isAjax()) {
  221. $this->layout = 'ajax';
  222. }
  223. if (Configure::read('Site.theme') && !isset($this->request->params['admin'])) {
  224. $this->theme = Configure::read('Site.theme');
  225. } elseif (Configure::read('Site.admin_theme') && isset($this->request->params['admin'])) {
  226. $this->theme = Configure::read('Site.admin_theme');
  227. }
  228. if (
  229. !isset($this->request->params['admin']) &&
  230. Configure::read('Site.status') == 0 &&
  231. $this->Auth->user('role_id') != 1
  232. ) {
  233. if (!$this->request->is('whitelisted')) {
  234. $this->layout = 'maintenance';
  235. $this->response->statusCode(503);
  236. $this->set('title_for_layout', __d('croogo', 'Site down for maintenance'));
  237. $this->render('../Elements/blank');
  238. }
  239. }
  240. if (isset($this->request->params['locale'])) {
  241. Configure::write('Config.language', $this->request->params['locale']);
  242. }
  243. if (isset($this->request->params['admin'])) {
  244. Croogo::dispatchEvent('Croogo.beforeSetupAdminData', $this);
  245. }
  246. }
  247. /**
  248. * blackHoleCallback for SecurityComponent
  249. *
  250. * @return void
  251. */
  252. public function securityError($type) {
  253. switch ($type) {
  254. case 'auth':
  255. break;
  256. case 'csrf':
  257. break;
  258. case 'get':
  259. break;
  260. case 'post':
  261. break;
  262. case 'put':
  263. break;
  264. case 'delete':
  265. break;
  266. default:
  267. break;
  268. }
  269. $this->set(compact('type'));
  270. $this->response = $this->render('../Errors/security');
  271. $this->response->statusCode(400);
  272. $this->response->send();
  273. $this->_stop();
  274. return false;
  275. }
  276. /**
  277. * _setupAclComponent
  278. */
  279. protected function _setupAclComponent() {
  280. $config = Configure::read('Access Control');
  281. if (isset($config['rowLevel']) && $config['rowLevel'] == true) {
  282. if (strpos($config['models'], $this->plugin . '.' . $this->modelClass) === false) {
  283. return;
  284. }
  285. $this->Components->load(Configure::read('Site.acl_plugin') . '.RowLevelAcl');
  286. }
  287. }
  288. /**
  289. * Combine add and edit views
  290. *
  291. * @see Controller::render()
  292. */
  293. public function render($view = null, $layout = null) {
  294. list($plugin, ) = pluginSplit(App::location(get_parent_class($this)));
  295. if ($plugin) {
  296. App::build(array(
  297. 'View' => array(
  298. CakePlugin::path($plugin) . 'View' . DS,
  299. ),
  300. ), App::APPEND);
  301. }
  302. if (strpos($view, '/') !== false || $this instanceof CakeErrorController) {
  303. return parent::render($view, $layout);
  304. }
  305. $fallbackView = $this->__getDefaultFallbackView();
  306. if (is_null($view) && in_array($this->request->action, array('admin_edit', 'admin_add', 'edit', 'add'))) {
  307. $viewPaths = App::path('View', $this->plugin);
  308. $themePath = $this->theme ? App::themePath($this->theme) : null;
  309. $searchPaths = array_merge((array)$themePath, $viewPaths);
  310. $view = $this->__findRequestedView($searchPaths);
  311. if (empty($view)) {
  312. $view = $fallbackView;
  313. }
  314. }
  315. return parent::render($view, $layout);
  316. }
  317. /**
  318. * Croogo uses this callback to load Paginator helper when one is not supplied.
  319. * This is required so that pagination variables are correctly set with caching
  320. * is used.
  321. *
  322. * @return void
  323. * @see Controller::beforeRender()
  324. */
  325. public function beforeRender() {
  326. if (!$this->usePaginationCache) {
  327. return;
  328. }
  329. if (!isset($this->helpers['Paginator']) && !in_array('Paginator', $this->helpers)) {
  330. $this->helpers[] = 'Paginator';
  331. }
  332. }
  333. /**
  334. * Get Default Fallback View
  335. *
  336. * @return string
  337. */
  338. private function __getDefaultFallbackView() {
  339. $fallbackView = 'form';
  340. if (!empty($this->request->params['prefix']) && $this->request->params['prefix'] === 'admin') {
  341. $fallbackView = 'admin_form';
  342. }
  343. return $fallbackView;
  344. }
  345. /**
  346. * Search for existing view override in registered view paths
  347. *
  348. * @return string
  349. */
  350. private function __findRequestedView($viewPaths) {
  351. if (empty($viewPaths)) {
  352. return false;
  353. }
  354. foreach ($viewPaths as $path) {
  355. $file = $this->viewPath . DS . $this->request->action . '.ctp';
  356. $requested = $path . $file;
  357. if (file_exists($requested)) {
  358. return $requested;
  359. } else {
  360. if (!$this->plugin) {
  361. continue;
  362. }
  363. $requested = $path . 'Plugin' . DS . $this->plugin . DS . $file;
  364. if (file_exists($requested)) {
  365. return $requested;
  366. }
  367. }
  368. }
  369. return false;
  370. }
  371. }