Controller.php 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. <?php
  2. /**
  3. * Base controller class.
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  8. * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice.
  12. *
  13. * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://cakephp.org CakePHP(tm) Project
  15. * @package cake.libs.controller
  16. * @since CakePHP(tm) v 0.2.9
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. /**
  20. * Include files
  21. */
  22. App::uses('CakeResponse', 'Network');
  23. App::uses('ClassRegistry', 'Utility');
  24. App::uses('ComponentCollection', 'Controller');
  25. App::uses('View', 'View');
  26. /**
  27. * Application controller class for organization of business logic.
  28. * Provides basic functionality, such as rendering views inside layouts,
  29. * automatic model availability, redirection, callbacks, and more.
  30. *
  31. * Controllers should provide a number of 'action' methods. These are public methods on the controller
  32. * that are not prefixed with a '_' and not part of Controller. Each action serves as an endpoint for
  33. * performing a specific action on a resource or collection of resources. For example adding or editing a new
  34. * object, or listing a set of objects.
  35. *
  36. * You can access request parameters, using `$this->request`. The request object contains all the POST, GET and FILES
  37. * that were part of the request.
  38. *
  39. * After performing the required actions, controllers are responsible for creating a response. This usually
  40. * takes the form of a generated View, or possibly a redirection to another controller action. In either case
  41. * `$this->response` allows you to manipulate all aspects of the response.
  42. *
  43. * Controllers are created by Dispatcher based on request parameters and routing. By default controllers and actions
  44. * use conventional names. For example `/posts/index` maps to `PostsController::index()`. You can re-map urls
  45. * using Router::connect().
  46. *
  47. * @package cake.libs.controller
  48. * @link http://book.cakephp.org/view/956/Introduction
  49. */
  50. class Controller extends Object {
  51. /**
  52. * The name of this controller. Controller names are plural, named after the model they manipulate.
  53. *
  54. * @var string
  55. * @link http://book.cakephp.org/view/959/Controller-Attributes
  56. */
  57. public $name = null;
  58. /**
  59. * An array containing the class names of models this controller uses.
  60. *
  61. * Example: `public $uses = array('Product', 'Post', 'Comment');`
  62. *
  63. * Can be set to array() to use no models. Can be set to false to
  64. * use no models and prevent the merging of $uses with AppController
  65. *
  66. * @var mixed A single name as a string or a list of names as an array.
  67. * @link http://book.cakephp.org/view/961/components-helpers-and-uses
  68. */
  69. public $uses = false;
  70. /**
  71. * An array containing the names of helpers this controller uses. The array elements should
  72. * not contain the "Helper" part of the classname.
  73. *
  74. * Example: `public $helpers = array('Html', 'Javascript', 'Time', 'Ajax');`
  75. *
  76. * @var mixed A single name as a string or a list of names as an array.
  77. * @link http://book.cakephp.org/view/961/components-helpers-and-uses
  78. */
  79. public $helpers = array('Session', 'Html', 'Form');
  80. /**
  81. * An instance of a CakeRequest object that contains information about the current request.
  82. * This object contains all the information about a request and several methods for reading
  83. * additional information about the request.
  84. *
  85. * @var CakeRequest
  86. */
  87. public $request;
  88. /**
  89. * An instance of a CakeResponse object that contains information about the impending response
  90. *
  91. * @var CakeResponse
  92. */
  93. public $response;
  94. /**
  95. * The classname to use for creating the response object.
  96. *
  97. * @var string
  98. */
  99. protected $_responseClass = 'CakeResponse';
  100. /**
  101. * The name of the views subfolder containing views for this controller.
  102. *
  103. * @var string
  104. */
  105. public $viewPath = null;
  106. /**
  107. * The name of the layouts subfolder containing layouts for this controller.
  108. *
  109. * @var string
  110. */
  111. public $layoutPath = null;
  112. /**
  113. * Contains variables to be handed to the view.
  114. *
  115. * @var array
  116. */
  117. public $viewVars = array();
  118. /**
  119. * An array containing the class names of the models this controller uses.
  120. *
  121. * @var array Array of model objects.
  122. */
  123. public $modelNames = array();
  124. /**
  125. * The name of the view file to render. The name specified
  126. * is the filename in /app/View/<SubFolder> without the .ctp extension.
  127. *
  128. * @var string
  129. * @link http://book.cakephp.org/view/962/Page-related-Attributes-layout-and-pageTitle
  130. */
  131. public $view = null;
  132. /**
  133. * The name of the layout file to render the view inside of. The name specified
  134. * is the filename of the layout in /app/View/Layouts without the .ctp
  135. * extension.
  136. *
  137. * @var string
  138. * @link http://book.cakephp.org/view/962/Page-related-Attributes-layout-and-pageTitle
  139. */
  140. public $layout = 'default';
  141. /**
  142. * Set to true to automatically render the view
  143. * after action logic.
  144. *
  145. * @var boolean
  146. */
  147. public $autoRender = true;
  148. /**
  149. * Set to true to automatically render the layout around views.
  150. *
  151. * @var boolean
  152. */
  153. public $autoLayout = true;
  154. /**
  155. * Instance of ComponentCollection used to handle callbacks.
  156. *
  157. * @var string
  158. */
  159. public $Components = null;
  160. /**
  161. * Array containing the names of components this controller uses. Component names
  162. * should not contain the "Component" portion of the classname.
  163. *
  164. * Example: `public $components = array('Session', 'RequestHandler', 'Acl');`
  165. *
  166. * @var array
  167. * @link http://book.cakephp.org/view/961/components-helpers-and-uses
  168. */
  169. public $components = array('Session');
  170. /**
  171. * The name of the View class this controller sends output to.
  172. *
  173. * @var string
  174. */
  175. public $viewClass = 'View';
  176. /**
  177. * Instance of the View created during rendering. Won't be set until after Controller::render() is called.
  178. *
  179. * @var View
  180. */
  181. public $View;
  182. /**
  183. * File extension for view templates. Defaults to Cake's conventional ".ctp".
  184. *
  185. * @var string
  186. */
  187. public $ext = '.ctp';
  188. /**
  189. * Automatically set to the name of a plugin.
  190. *
  191. * @var string
  192. */
  193. public $plugin = null;
  194. /**
  195. * Used to define methods a controller that will be cached. To cache a
  196. * single action, the value is set to an array containing keys that match
  197. * action names and values that denote cache expiration times (in seconds).
  198. *
  199. * Example:
  200. *
  201. * {{{
  202. * public $cacheAction = array(
  203. * 'view/23/' => 21600,
  204. * 'recalled/' => 86400
  205. * );
  206. * }}}
  207. *
  208. * $cacheAction can also be set to a strtotime() compatible string. This
  209. * marks all the actions in the controller for view caching.
  210. *
  211. * @var mixed
  212. * @link http://book.cakephp.org/view/1380/Caching-in-the-Controller
  213. */
  214. public $cacheAction = false;
  215. /**
  216. * Holds all params passed and named.
  217. *
  218. * @var mixed
  219. */
  220. public $passedArgs = array();
  221. /**
  222. * Triggers Scaffolding
  223. *
  224. * @var mixed
  225. * @link http://book.cakephp.org/view/1103/Scaffolding
  226. */
  227. public $scaffold = false;
  228. /**
  229. * Holds current methods of the controller. This is a list of all the methods reachable
  230. * via url. Modifying this array, will allow you to change which methods can be reached.
  231. *
  232. * @var array
  233. */
  234. public $methods = array();
  235. /**
  236. * This controller's primary model class name, the Inflector::classify()'ed version of
  237. * the controller's $name property.
  238. *
  239. * Example: For a controller named 'Comments', the modelClass would be 'Comment'
  240. *
  241. * @var string
  242. */
  243. public $modelClass = null;
  244. /**
  245. * This controller's model key name, an underscored version of the controller's $modelClass property.
  246. *
  247. * Example: For a controller named 'ArticleComments', the modelKey would be 'article_comment'
  248. *
  249. * @var string
  250. */
  251. public $modelKey = null;
  252. /**
  253. * Holds any validation errors produced by the last call of the validateErrors() method/
  254. *
  255. * @var array Validation errors, or false if none
  256. */
  257. public $validationErrors = null;
  258. /**
  259. * The class name of the parent class you wish to merge with.
  260. * Typically this is AppController, but you may wish to merge vars with a different
  261. * parent class.
  262. *
  263. * @var string
  264. */
  265. protected $_mergeParent = 'AppController';
  266. /**
  267. * Constructor.
  268. *
  269. * @param CakeRequest $request Request object for this controller can be null for testing.
  270. * But expect that features that use the params will not work.
  271. */
  272. public function __construct($request = null) {
  273. if ($this->name === null) {
  274. $this->name = substr(get_class($this), 0, strlen(get_class($this)) -10);
  275. }
  276. if ($this->viewPath == null) {
  277. $this->viewPath = $this->name;
  278. }
  279. $this->modelClass = Inflector::singularize($this->name);
  280. $this->modelKey = Inflector::underscore($this->modelClass);
  281. $this->Components = new ComponentCollection();
  282. $childMethods = get_class_methods($this);
  283. $parentMethods = get_class_methods('Controller');
  284. $this->methods = array_diff($childMethods, $parentMethods);
  285. if ($request instanceof CakeRequest) {
  286. $this->setRequest($request);
  287. }
  288. $this->getResponse();
  289. parent::__construct();
  290. }
  291. /**
  292. * Provides backwards compatibility to avoid problems with empty and isset to alias properties.
  293. * Lazy loads models using the loadModel() method if declared in $uses
  294. *
  295. * @return void
  296. */
  297. public function __isset($name) {
  298. switch ($name) {
  299. case 'base':
  300. case 'here':
  301. case 'webroot':
  302. case 'data':
  303. case 'action':
  304. case 'params':
  305. return true;
  306. }
  307. if (is_array($this->uses)) {
  308. foreach ($this->uses as $modelClass) {
  309. list($plugin, $class) = pluginSplit($modelClass, true);
  310. if ($name === $class) {
  311. if (!$plugin) {
  312. $plugin = $this->plugin ? $this->plugin . '.' : null;
  313. }
  314. return $this->loadModel($modelClass);
  315. }
  316. }
  317. }
  318. if ($name === $this->modelClass) {
  319. list($plugin, $class) = pluginSplit($name, true);
  320. if (!$plugin) {
  321. $plugin = $this->plugin ? $this->plugin . '.' : null;
  322. }
  323. return $this->loadModel($plugin . $this->modelClass);
  324. }
  325. return false;
  326. }
  327. /**
  328. * Provides backwards compatibility access to the request object properties.
  329. * Also provides the params alias.
  330. *
  331. * @return void
  332. */
  333. public function __get($name) {
  334. switch ($name) {
  335. case 'base':
  336. case 'here':
  337. case 'webroot':
  338. case 'data':
  339. return $this->request->{$name};
  340. case 'action':
  341. return isset($this->request->params['action']) ? $this->request->params['action'] : '';
  342. case 'params':
  343. return $this->request;
  344. case 'paginate':
  345. return $this->Components->load('Paginator')->settings;
  346. }
  347. if (isset($this->{$name})) {
  348. return $this->{$name};
  349. }
  350. return null;
  351. }
  352. /**
  353. * Provides backwards compatibility access for setting values to the request object.
  354. *
  355. * @return void
  356. */
  357. public function __set($name, $value) {
  358. switch ($name) {
  359. case 'base':
  360. case 'here':
  361. case 'webroot':
  362. case 'data':
  363. return $this->request->{$name} = $value;
  364. case 'action':
  365. return $this->request->params['action'] = $value;
  366. case 'params':
  367. return $this->request->params = $value;
  368. case 'paginate':
  369. return $this->Components->load('Paginator')->settings = $value;
  370. }
  371. return $this->{$name} = $value;
  372. }
  373. /**
  374. * Sets the request objects and configures a number of controller properties
  375. * based on the contents of the request. The properties that get set are
  376. *
  377. * - $this->request - To the $request parameter
  378. * - $this->plugin - To the $request->params['plugin']
  379. * - $this->view - To the $request->params['action']
  380. * - $this->autoLayout - To the false if $request->params['bare']; is set.
  381. * - $this->autoRender - To false if $request->params['return'] == 1
  382. * - $this->passedArgs - The the combined results of params['named'] and params['pass]
  383. *
  384. * @param CakeRequest $request
  385. * @return void
  386. */
  387. public function setRequest(CakeRequest $request) {
  388. $this->request = $request;
  389. $this->plugin = isset($request->params['plugin']) ? Inflector::camelize($request->params['plugin']) : null;
  390. $this->view = isset($request->params['action']) ? $request->params['action'] : null;
  391. if (isset($request->params['pass']) && isset($request->params['named'])) {
  392. $this->passedArgs = array_merge($request->params['pass'], $request->params['named']);
  393. }
  394. if (array_key_exists('return', $request->params) && $request->params['return'] == 1) {
  395. $this->autoRender = false;
  396. }
  397. if (!empty($request->params['bare'])) {
  398. $this->autoLayout = false;
  399. }
  400. }
  401. /**
  402. * Merge components, helpers, and uses vars from Controller::$_mergeParent and PluginAppController.
  403. *
  404. * @return void
  405. */
  406. protected function __mergeVars() {
  407. $pluginController = $pluginDot = null;
  408. if (!empty($this->plugin)) {
  409. $pluginController = $this->plugin . 'AppController';
  410. if (!is_subclass_of($this, $pluginController)) {
  411. $pluginController = null;
  412. }
  413. $pluginDot = $this->plugin . '.';
  414. }
  415. if (is_subclass_of($this, $this->_mergeParent) || !empty($pluginController)) {
  416. $appVars = get_class_vars($this->_mergeParent);
  417. $uses = $appVars['uses'];
  418. $merge = array('components', 'helpers');
  419. if ($uses == $this->uses && !empty($this->uses)) {
  420. if (!in_array($pluginDot . $this->modelClass, $this->uses)) {
  421. array_unshift($this->uses, $pluginDot . $this->modelClass);
  422. } elseif ($this->uses[0] !== $pluginDot . $this->modelClass) {
  423. $this->uses = array_flip($this->uses);
  424. unset($this->uses[$pluginDot . $this->modelClass]);
  425. $this->uses = array_flip($this->uses);
  426. array_unshift($this->uses, $pluginDot . $this->modelClass);
  427. }
  428. } elseif (
  429. ($this->uses !== null || $this->uses !== false) &&
  430. is_array($this->uses) && !empty($appVars['uses'])
  431. ) {
  432. $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses));
  433. }
  434. $this->_mergeVars($merge, $this->_mergeParent, true);
  435. }
  436. if ($pluginController && $this->plugin != null) {
  437. $merge = array('components', 'helpers');
  438. $appVars = get_class_vars($pluginController);
  439. if (
  440. ($this->uses !== null || $this->uses !== false) &&
  441. is_array($this->uses) && !empty($appVars['uses'])
  442. ) {
  443. $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses));
  444. }
  445. $this->_mergeVars($merge, $pluginController);
  446. }
  447. }
  448. /**
  449. * Loads Model classes based on the uses property
  450. * see Controller::loadModel(); for more info.
  451. * Loads Components and prepares them for initialization.
  452. *
  453. * @return mixed true if models found and instance created.
  454. * @see Controller::loadModel()
  455. * @link http://book.cakephp.org/view/977/Controller-Methods#constructClasses-986
  456. * @throws MissingModelException
  457. */
  458. public function constructClasses() {
  459. $this->__mergeVars();
  460. $this->Components->init($this);
  461. if ($this->uses) {
  462. $this->uses = (array) $this->uses;
  463. list(, $this->modelClass) = pluginSplit(current($this->uses));
  464. }
  465. return true;
  466. }
  467. /**
  468. * Gets the response object for this controller. Will construct the response if it has not already been built.
  469. *
  470. * @return CakeResponse
  471. */
  472. public function getResponse() {
  473. if (empty($this->response)) {
  474. $this->response = new $this->_responseClass(array('charset' => Configure::read('App.encoding')));
  475. }
  476. return $this->response;
  477. }
  478. /**
  479. * Perform the startup process for this controller.
  480. * Fire the Components and Controller callbacks in the correct order.
  481. *
  482. * - Initializes components, which fires their `initialize` callback
  483. * - Calls the controller `beforeFilter`.
  484. * - triggers Component `startup` methods.
  485. *
  486. * @return void
  487. */
  488. public function startupProcess() {
  489. $this->Components->trigger('initialize', array(&$this));
  490. $this->beforeFilter();
  491. $this->Components->trigger('startup', array(&$this));
  492. }
  493. /**
  494. * Perform the various shutdown processes for this controller.
  495. * Fire the Components and Controller callbacks in the correct order.
  496. *
  497. * - triggers the component `shutdown` callback.
  498. * - calls the Controller's `afterFilter` method.
  499. *
  500. * @return void
  501. */
  502. public function shutdownProcess() {
  503. $this->Components->trigger('shutdown', array(&$this));
  504. $this->afterFilter();
  505. }
  506. /**
  507. * Queries & sets valid HTTP response codes & messages.
  508. *
  509. * @param mixed $code If $code is an integer, then the corresponding code/message is
  510. * returned if it exists, null if it does not exist. If $code is an array,
  511. * then the 'code' and 'message' keys of each nested array are added to the default
  512. * HTTP codes. Example:
  513. *
  514. * httpCodes(404); // returns array(404 => 'Not Found')
  515. *
  516. * httpCodes(array(
  517. * 701 => 'Unicorn Moved',
  518. * 800 => 'Unexpected Minotaur'
  519. * )); // sets these new values, and returns true
  520. *
  521. * @return mixed Associative array of the HTTP codes as keys, and the message
  522. * strings as values, or null of the given $code does not exist.
  523. * @deprecated Use CakeResponse::httpCodes();
  524. */
  525. public function httpCodes($code = null) {
  526. return $this->response->httpCodes($code);
  527. }
  528. /**
  529. * Loads and instantiates models required by this controller.
  530. * If the model is non existent, it will throw a missing database table error, as Cake generates
  531. * dynamic models for the time being.
  532. *
  533. * @param string $modelClass Name of model class to load
  534. * @param mixed $id Initial ID the instanced model class should have
  535. * @return mixed true when single model found and instance created, error returned if model not found.
  536. * @throws MissingModelException if the model class cannot be found.
  537. */
  538. public function loadModel($modelClass = null, $id = null) {
  539. if ($modelClass === null) {
  540. $modelClass = $this->modelClass;
  541. }
  542. list($plugin, $modelClass) = pluginSplit($modelClass, true);
  543. $this->modelNames[] = $modelClass;
  544. $this->{$modelClass} = ClassRegistry::init(array(
  545. 'class' => $plugin . $modelClass, 'alias' => $modelClass, 'id' => $id
  546. ));
  547. if (!$this->{$modelClass}) {
  548. throw new MissingModelException($modelClass);
  549. }
  550. return true;
  551. }
  552. /**
  553. * Redirects to given $url, after turning off $this->autoRender.
  554. * Script execution is halted after the redirect.
  555. *
  556. * @param mixed $url A string or array-based URL pointing to another location within the app,
  557. * or an absolute URL
  558. * @param integer $status Optional HTTP status code (eg: 404)
  559. * @param boolean $exit If true, exit() will be called after the redirect
  560. * @return mixed void if $exit = false. Terminates script if $exit = true
  561. * @link http://book.cakephp.org/view/982/redirect
  562. */
  563. public function redirect($url, $status = null, $exit = true) {
  564. $this->autoRender = false;
  565. if (is_array($status)) {
  566. extract($status, EXTR_OVERWRITE);
  567. }
  568. $response = $this->Components->trigger(
  569. 'beforeRedirect',
  570. array(&$this, $url, $status, $exit),
  571. array('break' => true, 'breakOn' => false, 'collectReturn' => true)
  572. );
  573. if ($response === false) {
  574. return;
  575. }
  576. extract($this->_parseBeforeRedirect($response, $url, $status, $exit), EXTR_OVERWRITE);
  577. $response = $this->beforeRedirect($url, $status, $exit);
  578. if ($response === false) {
  579. return;
  580. }
  581. extract($this->_parseBeforeRedirect($response, $url, $status, $exit), EXTR_OVERWRITE);
  582. if (function_exists('session_write_close')) {
  583. session_write_close();
  584. }
  585. if (!empty($status) && is_string($status)) {
  586. $codes = array_flip($this->response->httpCodes());
  587. if (isset($codes[$status])) {
  588. $status = $codes[$status];
  589. }
  590. }
  591. if ($url !== null) {
  592. $this->response->header('Location', Router::url($url, true));
  593. }
  594. if (!empty($status) && ($status >= 300 && $status < 400)) {
  595. $this->response->statusCode($status);
  596. }
  597. if ($exit) {
  598. $this->response->send();
  599. $this->_stop();
  600. }
  601. }
  602. /**
  603. * Parse beforeRedirect Response
  604. *
  605. * @param mixed $response Response from beforeRedirect callback
  606. * @param mixed $url The same value of beforeRedirect
  607. * @param integer $status The same value of beforeRedirect
  608. * @param boolean $exit The same value of beforeRedirect
  609. * @return array Array with keys url, status and exit
  610. */
  611. protected function _parseBeforeRedirect($response, $url, $status, $exit) {
  612. if (is_array($response)) {
  613. foreach ($response as $resp) {
  614. if (is_array($resp) && isset($resp['url'])) {
  615. extract($resp, EXTR_OVERWRITE);
  616. } elseif ($resp !== null) {
  617. $url = $resp;
  618. }
  619. }
  620. }
  621. return compact('url', 'status', 'exit');
  622. }
  623. /**
  624. * Convenience and object wrapper method for CakeResponse::header().
  625. *
  626. * @param string $status The header message that is being set.
  627. * @return void
  628. * @deprecated Use CakeResponse::header()
  629. */
  630. public function header($status) {
  631. $this->response->header($status);
  632. }
  633. /**
  634. * Saves a variable for use inside a view template.
  635. *
  636. * @param mixed $one A string or an array of data.
  637. * @param mixed $two Value in case $one is a string (which then works as the key).
  638. * Unused if $one is an associative array, otherwise serves as the values to $one's keys.
  639. * @return void
  640. * @link http://book.cakephp.org/view/979/set
  641. */
  642. public function set($one, $two = null) {
  643. if (is_array($one)) {
  644. if (is_array($two)) {
  645. $data = array_combine($one, $two);
  646. } else {
  647. $data = $one;
  648. }
  649. } else {
  650. $data = array($one => $two);
  651. }
  652. $this->viewVars = $data + $this->viewVars;
  653. }
  654. /**
  655. * Internally redirects one action to another. Does not perform another HTTP request unlike Controller::redirect()
  656. *
  657. * Examples:
  658. *
  659. * {{{
  660. * setAction('another_action');
  661. * setAction('action_with_parameters', $parameter1);
  662. * }}}
  663. *
  664. * @param string $action The new action to be 'redirected' to
  665. * @param mixed Any other parameters passed to this method will be passed as
  666. * parameters to the new action.
  667. * @return mixed Returns the return value of the called action
  668. */
  669. public function setAction($action) {
  670. $this->request->action = $action;
  671. $args = func_get_args();
  672. unset($args[0]);
  673. return call_user_func_array(array(&$this, $action), $args);
  674. }
  675. /**
  676. * Returns number of errors in a submitted FORM.
  677. *
  678. * @return integer Number of errors
  679. */
  680. public function validate() {
  681. $args = func_get_args();
  682. $errors = call_user_func_array(array(&$this, 'validateErrors'), $args);
  683. if ($errors === false) {
  684. return 0;
  685. }
  686. return count($errors);
  687. }
  688. /**
  689. * Validates models passed by parameters. Example:
  690. *
  691. * `$errors = $this->validateErrors($this->Article, $this->User);`
  692. *
  693. * @param mixed A list of models as a variable argument
  694. * @return array Validation errors, or false if none
  695. */
  696. public function validateErrors() {
  697. $objects = func_get_args();
  698. if (empty($objects)) {
  699. return false;
  700. }
  701. $errors = array();
  702. foreach ($objects as $object) {
  703. if (isset($this->{$object->alias})) {
  704. $object = $this->{$object->alias};
  705. }
  706. $object->set($object->data);
  707. $errors = array_merge($errors, $object->invalidFields());
  708. }
  709. return $this->validationErrors = (!empty($errors) ? $errors : false);
  710. }
  711. /**
  712. * Instantiates the correct view class, hands it its data, and uses it to render the view output.
  713. *
  714. * @param string $view View to use for rendering
  715. * @param string $layout Layout to use
  716. * @return string Full output string of view contents
  717. * @link http://book.cakephp.org/view/980/render
  718. */
  719. public function render($view = null, $layout = null) {
  720. $this->beforeRender();
  721. $this->Components->trigger('beforeRender', array(&$this));
  722. $viewClass = $this->viewClass;
  723. if ($this->viewClass != 'View') {
  724. list($plugin, $viewClass) = pluginSplit($viewClass, true);
  725. $viewClass = $viewClass . 'View';
  726. App::uses($viewClass, $plugin . 'View');
  727. }
  728. $this->request->params['models'] = $this->modelNames;
  729. $View = new $viewClass($this);
  730. if (!empty($this->modelNames)) {
  731. $models = array();
  732. foreach ($this->modelNames as $currentModel) {
  733. if (isset($this->$currentModel) && is_a($this->$currentModel, 'Model')) {
  734. $models[] = Inflector::underscore($currentModel);
  735. }
  736. $isValidModel = (
  737. isset($this->$currentModel) && is_a($this->$currentModel, 'Model') &&
  738. !empty($this->$currentModel->validationErrors)
  739. );
  740. if ($isValidModel) {
  741. $View->validationErrors[Inflector::camelize($currentModel)] =&
  742. $this->$currentModel->validationErrors;
  743. }
  744. }
  745. $models = array_diff(ClassRegistry::keys(), $models);
  746. foreach ($models as $currentModel) {
  747. if (ClassRegistry::isKeySet($currentModel)) {
  748. $currentObject = ClassRegistry::getObject($currentModel);
  749. if (is_a($currentObject, 'Model') && !empty($currentObject->validationErrors)) {
  750. $View->validationErrors[Inflector::camelize($currentModel)] =&
  751. $currentObject->validationErrors;
  752. }
  753. }
  754. }
  755. }
  756. $this->autoRender = false;
  757. $this->View = $View;
  758. return $this->response->body($View->render($view, $layout));
  759. }
  760. /**
  761. * Returns the referring URL for this request.
  762. *
  763. * @param string $default Default URL to use if HTTP_REFERER cannot be read from headers
  764. * @param boolean $local If true, restrict referring URLs to local server
  765. * @return string Referring URL
  766. * @link http://book.cakephp.org/view/987/referer
  767. */
  768. public function referer($default = null, $local = false) {
  769. if ($this->request) {
  770. $referer = $this->request->referer($local);
  771. if ($referer == '/' && $default != null) {
  772. return Router::url($default, true);
  773. }
  774. return $referer;
  775. }
  776. return '/';
  777. }
  778. /**
  779. * Forces the user's browser not to cache the results of the current request.
  780. *
  781. * @return void
  782. * @link http://book.cakephp.org/view/988/disableCache
  783. * @deprecated Use CakeResponse::disableCache()
  784. */
  785. public function disableCache() {
  786. $this->response->disableCache();
  787. }
  788. /**
  789. * Shows a message to the user for $pause seconds, then redirects to $url.
  790. * Uses flash.ctp as the default layout for the message.
  791. * Does not work if the current debug level is higher than 0.
  792. *
  793. * @param string $message Message to display to the user
  794. * @param mixed $url Relative string or array-based URL to redirect to after the time expires
  795. * @param integer $pause Time to show the message
  796. * @param string $layout Layout you want to use, defaults to 'flash'
  797. * @return void Renders flash layout
  798. * @link http://book.cakephp.org/view/983/flash
  799. */
  800. public function flash($message, $url, $pause = 1, $layout = 'flash') {
  801. $this->autoRender = false;
  802. $this->set('url', Router::url($url));
  803. $this->set('message', $message);
  804. $this->set('pause', $pause);
  805. $this->set('page_title', $message);
  806. $this->response->body($this->render(false, $layout));
  807. }
  808. /**
  809. * Converts POST'ed form data to a model conditions array, suitable for use in a Model::find() call.
  810. *
  811. * @param array $data POST'ed data organized by model and field
  812. * @param mixed $op A string containing an SQL comparison operator, or an array matching operators
  813. * to fields
  814. * @param string $bool SQL boolean operator: AND, OR, XOR, etc.
  815. * @param boolean $exclusive If true, and $op is an array, fields not included in $op will not be
  816. * included in the returned conditions
  817. * @return array An array of model conditions
  818. * @link http://book.cakephp.org/view/989/postConditions
  819. */
  820. public function postConditions($data = array(), $op = null, $bool = 'AND', $exclusive = false) {
  821. if (!is_array($data) || empty($data)) {
  822. if (!empty($this->request->data)) {
  823. $data = $this->request->data;
  824. } else {
  825. return null;
  826. }
  827. }
  828. $cond = array();
  829. if ($op === null) {
  830. $op = '';
  831. }
  832. $arrayOp = is_array($op);
  833. foreach ($data as $model => $fields) {
  834. foreach ($fields as $field => $value) {
  835. $key = $model.'.'.$field;
  836. $fieldOp = $op;
  837. if ($arrayOp) {
  838. if (array_key_exists($key, $op)) {
  839. $fieldOp = $op[$key];
  840. } elseif (array_key_exists($field, $op)) {
  841. $fieldOp = $op[$field];
  842. } else {
  843. $fieldOp = false;
  844. }
  845. }
  846. if ($exclusive && $fieldOp === false) {
  847. continue;
  848. }
  849. $fieldOp = strtoupper(trim($fieldOp));
  850. if ($fieldOp === 'LIKE') {
  851. $key = $key.' LIKE';
  852. $value = '%'.$value.'%';
  853. } elseif ($fieldOp && $fieldOp != '=') {
  854. $key = $key.' '.$fieldOp;
  855. }
  856. $cond[$key] = $value;
  857. }
  858. }
  859. if ($bool != null && strtoupper($bool) != 'AND') {
  860. $cond = array($bool => $cond);
  861. }
  862. return $cond;
  863. }
  864. /**
  865. * Handles automatic pagination of model records.
  866. *
  867. * @param mixed $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
  868. * @param mixed $scope Conditions to use while paginating
  869. * @param array $whitelist List of allowed options for paging
  870. * @return array Model query results
  871. * @link http://book.cakephp.org/view/1232/Controller-Setup
  872. * @deprecated Use PaginatorComponent instead
  873. */
  874. public function paginate($object = null, $scope = array(), $whitelist = array()) {
  875. return $this->Components->load('Paginator', $this->paginate)->paginate($object, $scope, $whitelist);
  876. }
  877. /**
  878. * Called before the controller action. You can use this method to configure and customize components
  879. * or perform logic that needs to happen before each controller action.
  880. *
  881. * @link http://book.cakephp.org/view/984/Callbacks
  882. */
  883. public function beforeFilter() {
  884. }
  885. /**
  886. * Called after the controller action is run, but before the view is rendered. You can use this method
  887. * to perform logic or set view variables that are required on every request.
  888. *
  889. * @link http://book.cakephp.org/view/984/Callbacks
  890. */
  891. public function beforeRender() {
  892. }
  893. /**
  894. * The beforeRedirect method is invoked when the controller's redirect method is called but before any
  895. * further action. If this method returns false the controller will not continue on to redirect the request.
  896. * The $url, $status and $exit variables have same meaning as for the controller's method. You can also
  897. * return a string which will be interpreted as the url to redirect to or return associative array with
  898. * key 'url' and optionally 'status' and 'exit'.
  899. *
  900. * @param mixed $url A string or array-based URL pointing to another location within the app,
  901. * or an absolute URL
  902. * @param integer $status Optional HTTP status code (eg: 404)
  903. * @param boolean $exit If true, exit() will be called after the redirect
  904. * @return boolean
  905. */
  906. public function beforeRedirect($url, $status = null, $exit = true) {
  907. return true;
  908. }
  909. /**
  910. * Called after the controller action is run and rendered.
  911. *
  912. * @link http://book.cakephp.org/view/984/Callbacks
  913. */
  914. public function afterFilter() {
  915. }
  916. /**
  917. * This method should be overridden in child classes.
  918. *
  919. * @param string $method name of method called example index, edit, etc.
  920. * @return boolean Success
  921. * @link http://book.cakephp.org/view/984/Callbacks
  922. */
  923. public function _beforeScaffold($method) {
  924. return true;
  925. }
  926. /**
  927. * This method should be overridden in child classes.
  928. *
  929. * @param string $method name of method called either edit or update.
  930. * @return boolean Success
  931. * @link http://book.cakephp.org/view/984/Callbacks
  932. */
  933. public function _afterScaffoldSave($method) {
  934. return true;
  935. }
  936. /**
  937. * This method should be overridden in child classes.
  938. *
  939. * @param string $method name of method called either edit or update.
  940. * @return boolean Success
  941. * @link http://book.cakephp.org/view/984/Callbacks
  942. */
  943. public function _afterScaffoldSaveError($method) {
  944. return true;
  945. }
  946. /**
  947. * This method should be overridden in child classes.
  948. * If not it will render a scaffold error.
  949. * Method MUST return true in child classes
  950. *
  951. * @param string $method name of method called example index, edit, etc.
  952. * @return boolean Success
  953. * @link http://book.cakephp.org/view/984/Callbacks
  954. */
  955. public function _scaffoldError($method) {
  956. return false;
  957. }
  958. }