controller.php 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /**
  4. * Base controller class.
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * CakePHP : Rapid Development Framework <http://www.cakephp.org/>
  9. * Copyright (c) 2006, Cake Software Foundation, Inc.
  10. * 1785 E. Sahara Avenue, Suite 490-204
  11. * Las Vegas, Nevada 89104
  12. *
  13. * Licensed under The MIT License
  14. * Redistributions of files must retain the above copyright notice.
  15. *
  16. * @filesource
  17. * @copyright Copyright (c) 2006, Cake Software Foundation, Inc.
  18. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
  19. * @package cake
  20. * @subpackage cake.cake.libs.controller
  21. * @since CakePHP v 0.2.9
  22. * @version $Revision$
  23. * @modifiedby $LastChangedBy$
  24. * @lastmodified $Date$
  25. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  26. */
  27. /**
  28. * Include files
  29. */
  30. uses('controller' . DS . 'component', 'view' . DS . 'view');
  31. /**
  32. * Controller
  33. *
  34. * Application controller (controllers are where you put all the actual code)
  35. * Provides basic functionality, such as rendering views (aka displaying templates).
  36. * Automatically selects model name from on singularized object class name
  37. * and creates the model object if proper class exists.
  38. *
  39. * @package cake
  40. * @subpackage cake.cake.libs.controller
  41. *
  42. */
  43. class Controller extends Object {
  44. /**
  45. * Name of the controller.
  46. *
  47. * @var string
  48. * @access public
  49. */
  50. var $name = null;
  51. /**
  52. * Stores the current URL (for links etc.)
  53. *
  54. * @var string
  55. * @access public
  56. */
  57. var $here = null;
  58. /**
  59. * The webroot of the application
  60. *
  61. * @var string
  62. * @access public
  63. */
  64. var $webroot = null;
  65. /**
  66. * Action to be performed.
  67. *
  68. * @var string
  69. * @access public
  70. */
  71. var $action = null;
  72. /**
  73. * An array of names of models the particular controller wants to use.
  74. *
  75. * @var mixed A single name as a string or a list of names as an array.
  76. * @access protected
  77. */
  78. var $uses = false;
  79. /**
  80. * An array of names of built-in helpers to include.
  81. *
  82. * @var mixed A single name as a string or a list of names as an array.
  83. * @access protected
  84. */
  85. var $helpers = array('Html');
  86. /**
  87. * Parameters received in the current request, i.e. GET and POST data
  88. *
  89. * @var array
  90. * @access public
  91. */
  92. var $params = array();
  93. /**
  94. * POST'ed model data
  95. *
  96. * @var array
  97. * @access public
  98. */
  99. var $data = array();
  100. /**
  101. * Pagination defaults
  102. *
  103. * @var array
  104. * @access public
  105. */
  106. var $paginate = array('limit' => 20, 'page' => 1);
  107. /**
  108. * Sub-path for view files
  109. *
  110. * @var string
  111. */
  112. var $viewPath = null;
  113. /**
  114. * Sub-path for layout files
  115. *
  116. * @var string
  117. */
  118. var $layoutPath = null;
  119. /**
  120. * Variables for the view
  121. *
  122. * @var array
  123. * @access public
  124. */
  125. var $viewVars = array();
  126. /**
  127. * Web page title
  128. *
  129. * @var boolean
  130. * @access public
  131. */
  132. var $pageTitle = false;
  133. /**
  134. * An array of model objects.
  135. *
  136. * @var array Array of model objects.
  137. * @access public
  138. */
  139. var $modelNames = array();
  140. /**
  141. * Base url path
  142. *
  143. * @var string
  144. * @access public
  145. */
  146. var $base = null;
  147. /**
  148. * Layout file to use (see /app/views/layouts/default.thtml)
  149. *
  150. * @var string
  151. * @access public
  152. */
  153. var $layout = 'default';
  154. /**
  155. * Automatically render the view (the dispatcher checks for this variable before running render())
  156. *
  157. * @var boolean
  158. * @access public
  159. */
  160. var $autoRender = true;
  161. /**
  162. * Automatically render the layout
  163. *
  164. * @var boolean
  165. * @access public
  166. */
  167. var $autoLayout = true;
  168. /**
  169. * Array of components a controller will use
  170. *
  171. * @var array
  172. * @access public
  173. */
  174. var $components = array();
  175. /**
  176. * The name of the View class a controller sends output to
  177. *
  178. * @var string
  179. * @access public
  180. */
  181. var $view = 'View';
  182. /**
  183. * File extension for view templates. Defaults to Cake's conventional ".thtml".
  184. *
  185. * @var string
  186. * @access public
  187. */
  188. var $ext = '.ctp';
  189. /**
  190. * Instance of $view class create by a controller
  191. *
  192. * @var object
  193. * @access private
  194. */
  195. var $__viewClass = null;
  196. /**
  197. * The output of the requested action. Contains either a variable
  198. * returned from the action, or the data of the rendered view;
  199. * You can use this var in Child classes afterFilter() to alter output.
  200. *
  201. * @var string
  202. * @access public
  203. */
  204. var $output = null;
  205. /**
  206. * Automatically set to the name of a plugin.
  207. *
  208. * @var string
  209. * @access public
  210. */
  211. var $plugin = null;
  212. /**
  213. * Used to set methods a controller will allow the View to cache
  214. *
  215. * @var mixed
  216. * @access public
  217. */
  218. var $cacheAction = false;
  219. /**
  220. * Used to create cached instances of models a controller uses.
  221. * When set to true all models related to the controller will be cached,
  222. * this can increase performance in many cases
  223. *
  224. * @var boolean
  225. * @access public
  226. */
  227. var $persistModel = false;
  228. /**
  229. * Enter description here...
  230. *
  231. * @var unknown_type
  232. */
  233. var $webservices = null;
  234. /**
  235. * Enter description here...
  236. *
  237. * @var mixed
  238. */
  239. var $namedArgs = true;
  240. /**
  241. * Enter description here...
  242. *
  243. * @var string
  244. */
  245. var $argSeparator = ':';
  246. /**
  247. * Constructor.
  248. *
  249. */
  250. function __construct() {
  251. if ($this->name === null) {
  252. $r = null;
  253. if (!preg_match('/(.*)Controller/i', get_class($this), $r)) {
  254. die (__("Controller::__construct() : Can not get or parse my own class name, exiting."));
  255. }
  256. $this->name = $r[1];
  257. }
  258. if ($this->viewPath == null) {
  259. $this->viewPath = Inflector::underscore($this->name);
  260. }
  261. $this->modelClass = Inflector::classify($this->name);
  262. $this->modelKey = Inflector::underscore($this->modelClass);
  263. if (is_subclass_of($this, 'AppController')) {
  264. $appVars = get_class_vars('AppController');
  265. $uses = $appVars['uses'];
  266. $merge = array('components', 'helpers');
  267. if ($uses == $this->uses && !empty($this->uses)) {
  268. array_unshift($this->uses, $this->modelClass);
  269. } elseif ($this->uses !== null || $this->uses !== false) {
  270. $merge[] = 'uses';
  271. }
  272. foreach($merge as $var) {
  273. if (isset($appVars[$var]) && !empty($appVars[$var]) && is_array($this->{$var})) {
  274. $this->{$var} = array_merge($this->{$var}, array_diff($appVars[$var], $this->{$var}));
  275. }
  276. }
  277. }
  278. parent::__construct();
  279. }
  280. function _initComponents() {
  281. $component = new Component();
  282. $component->init($this);
  283. }
  284. /**
  285. * Loads and instantiates models required by this controller.
  286. * If Controller::persistModel; is true, controller will create cached model instances on first request,
  287. * additional request will used cached models
  288. *
  289. * @return mixed true when single model found and instance created error returned if models not found.
  290. * @access public
  291. */
  292. function constructClasses() {
  293. if($this->uses === null || ($this->uses === array())){
  294. return false;
  295. }
  296. if (empty($this->passedArgs) || !isset($this->passedArgs['0'])) {
  297. $id = false;
  298. } else {
  299. $id = $this->passedArgs['0'];
  300. }
  301. $cached = false;
  302. $object = null;
  303. if($this->uses === false) {
  304. if(!class_exists($this->modelClass)){
  305. loadModel($this->modelClass);
  306. }
  307. }
  308. if (class_exists($this->modelClass) && ($this->uses === false)) {
  309. if ($this->persistModel === true) {
  310. $cached = $this->_persist($this->modelClass, null, $object);
  311. }
  312. if (($cached === false)) {
  313. $model =& new $this->modelClass($id);
  314. $this->modelNames[] = $this->modelClass;
  315. $this->{$this->modelClass} =& $model;
  316. if ($this->persistModel === true) {
  317. $this->_persist($this->modelClass, true, $model);
  318. $registry = ClassRegistry::getInstance();
  319. $this->_persist($this->modelClass . 'registry', true, $registry->_objects, 'registry');
  320. }
  321. } else {
  322. $this->_persist($this->modelClass . 'registry', true, $object, 'registry');
  323. $this->_persist($this->modelClass, true, $object);
  324. $this->modelNames[] = $this->modelClass;
  325. }
  326. return true;
  327. } elseif ($this->uses === false) {
  328. return $this->cakeError('missingModel', array(array('className' => $this->modelClass, 'webroot' => '', 'base' => $this->base)));
  329. }
  330. if ($this->uses) {
  331. $uses = is_array($this->uses) ? $this->uses : array($this->uses);
  332. foreach($uses as $modelClass) {
  333. $id = false;
  334. $cached = false;
  335. $object = null;
  336. $modelKey = Inflector::underscore($modelClass);
  337. if(!class_exists($modelClass)){
  338. loadModel($modelClass);
  339. }
  340. if (class_exists($modelClass)) {
  341. if ($this->persistModel === true) {
  342. $cached = $this->_persist($modelClass, null, $object);
  343. }
  344. if (($cached === false)) {
  345. $model =& new $modelClass($id);
  346. $this->modelNames[] = $modelClass;
  347. $this->{$modelClass} =& $model;
  348. if ($this->persistModel === true) {
  349. $this->_persist($modelClass, true, $model);
  350. $registry = ClassRegistry::getInstance();
  351. $this->_persist($modelClass . 'registry', true, $registry->_objects, 'registry');
  352. }
  353. } else {
  354. $this->_persist($modelClass . 'registry', true, $object, 'registry');
  355. $this->_persist($modelClass, true, $object);
  356. $this->modelNames[] = $modelClass;
  357. }
  358. } else {
  359. return $this->cakeError('missingModel', array(array('className' => $modelClass, 'webroot' => '', 'base' => $this->base)));
  360. }
  361. }
  362. return true;
  363. }
  364. }
  365. /**
  366. * Redirects to given $url, after turning off $this->autoRender.
  367. * Please notice that the script execution is not stopped after the redirect.
  368. *
  369. * @param mixed $url A string or array-based URL pointing to another location
  370. * within the app, or an absolute URL
  371. * @param integer $status Optional HTTP status code
  372. * @param boolean $exit If true, exit() will be called after the redirect
  373. * @access public
  374. */
  375. function redirect($url, $status = null, $exit = false) {
  376. $this->autoRender = false;
  377. if (is_array($status)) {
  378. extract($status, EXTR_OVERWRITE);
  379. }
  380. if (function_exists('session_write_close')) {
  381. session_write_close();
  382. }
  383. if (is_numeric($status) && $status > 0) {
  384. $codes = array(
  385. 100 => "Continue",
  386. 101 => "Switching Protocols",
  387. 200 => "OK",
  388. 201 => "Created",
  389. 202 => "Accepted",
  390. 203 => "Non-Authoritative Information",
  391. 204 => "No Content",
  392. 205 => "Reset Content",
  393. 206 => "Partial Content",
  394. 300 => "Multiple Choices",
  395. 301 => "Moved Permanently",
  396. 302 => "Found",
  397. 303 => "See Other",
  398. 304 => "Not Modified",
  399. 305 => "Use Proxy",
  400. 307 => "Temporary Redirect",
  401. 400 => "Bad Request",
  402. 401 => "Unauthorized",
  403. 402 => "Payment Required",
  404. 403 => "Forbidden",
  405. 404 => "Not Found",
  406. 405 => "Method Not Allowed",
  407. 406 => "Not Acceptable",
  408. 407 => "Proxy Authentication Required",
  409. 408 => "Request Time-out",
  410. 409 => "Conflict",
  411. 410 => "Gone",
  412. 411 => "Length Required",
  413. 412 => "Precondition Failed",
  414. 413 => "Request Entity Too Large",
  415. 414 => "Request-URI Too Large",
  416. 415 => "Unsupported Media Type",
  417. 416 => "Requested range not satisfiable",
  418. 417 => "Expectation Failed",
  419. 500 => "Internal Server Error",
  420. 501 => "Not Implemented",
  421. 502 => "Bad Gateway",
  422. 503 => "Service Unavailable",
  423. 504 => "Gateway Time-out"
  424. );
  425. if (isset($codes[$status])) {
  426. header("HTTP/1.1 {$status} " . $codes[$status]);
  427. }
  428. }
  429. if ($url !== null) {
  430. header('Location: ' . Router::url($url, defined('SERVER_IIS')));
  431. }
  432. if ($exit) {
  433. exit();
  434. }
  435. }
  436. /**
  437. * Saves a variable to use inside a template.
  438. *
  439. * @param mixed $one A string or an array of data.
  440. * @param mixed $two Value in case $one is a string (which then works as the key).
  441. * Unused if $one is an associative array, otherwise serves as the values to $one's keys.
  442. * @return void
  443. */
  444. function set($one, $two = null) {
  445. $data = array();
  446. if (is_array($one)) {
  447. if (is_array($two)) {
  448. $data = array_combine($one, $two);
  449. } else {
  450. $data = $one;
  451. }
  452. } else {
  453. $data = array($one => $two);
  454. }
  455. foreach($data as $name => $value) {
  456. if ($name == 'title') {
  457. $this->pageTitle = $value;
  458. } else {
  459. $this->viewVars[$name] = $value;
  460. }
  461. }
  462. }
  463. /**
  464. * Internally redirects one action to another
  465. *
  466. * @param string $action The new action to be redirected to
  467. * @param mixed Any other parameters passed to this method will be passed as
  468. * parameters to the new action.
  469. */
  470. function setAction($action) {
  471. $this->action = $action;
  472. $args = func_get_args();
  473. unset($args[0]);
  474. call_user_func_array(array(&$this, $action), $args);
  475. }
  476. /**
  477. * Returns number of errors in a submitted FORM.
  478. *
  479. * @return int Number of errors
  480. */
  481. function validate() {
  482. $args = func_get_args();
  483. $errors = call_user_func_array(array(&$this, 'validateErrors'), $args);
  484. if ($errors === false) {
  485. return 0;
  486. }
  487. return count($errors);
  488. }
  489. /**
  490. * Validates a FORM according to the rules set up in the Model.
  491. *
  492. * @return int Number of errors
  493. */
  494. function validateErrors() {
  495. $objects = func_get_args();
  496. if (!count($objects)) {
  497. return false;
  498. }
  499. $errors = array();
  500. foreach($objects as $object) {
  501. $errors = array_merge($errors, $this->{$object->name}->invalidFields($object->data));
  502. }
  503. return $this->validationErrors = (count($errors) ? $errors : false);
  504. }
  505. /**
  506. * Gets an instance of the view object & prepares it for rendering the output, then
  507. * asks the view to actualy do the job.
  508. *
  509. * @param unknown_type $action
  510. * @param unknown_type $layout
  511. * @param unknown_type $file
  512. * @return unknown
  513. */
  514. function render($action = null, $layout = null, $file = null) {
  515. $viewClass = $this->view;
  516. if ($this->view != 'View') {
  517. $viewClass = $this->view . 'View';
  518. loadView($this->view);
  519. }
  520. $this->beforeRender();
  521. $this->params['models'] = $this->modelNames;
  522. $this->__viewClass =& new $viewClass($this);
  523. if (!empty($this->modelNames)) {
  524. $count = count($this->modelNames);
  525. for ($i = 0; $i < $count; $i++) {
  526. $model = $this->modelNames[$i];
  527. if (!empty($this->{$model}->validationErrors)) {
  528. $this->__viewClass->validationErrors[$model] = &$this->{$model}->validationErrors;
  529. }
  530. }
  531. }
  532. $this->autoRender = false;
  533. return $this->__viewClass->render($action, $layout, $file);
  534. }
  535. /**
  536. * Gets the referring URL of this request
  537. *
  538. * @param string $default Default URL to use if HTTP_REFERER cannot be read from headers
  539. * @param boolean $local If true, restrict referring URLs to local server
  540. * @access public
  541. */
  542. function referer($default = null, $local = false) {
  543. $ref = env('HTTP_REFERER');
  544. $base = FULL_BASE_URL . $this->webroot;
  545. if ($ref != null && defined('FULL_BASE_URL')) {
  546. if (strpos($ref, $base) === 0) {
  547. return substr($ref, strlen($base) - 1);
  548. } elseif(!$local) {
  549. return $ref;
  550. }
  551. }
  552. if ($default != null) {
  553. return $default;
  554. } else {
  555. return '/';
  556. }
  557. }
  558. /**
  559. * Tells the browser not to cache the results of the current request
  560. *
  561. * @return void
  562. * @access public
  563. */
  564. function disableCache() {
  565. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  566. header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
  567. header("Cache-Control: no-store, no-cache, must-revalidate");
  568. header("Cache-Control: post-check=0, pre-check=0", false);
  569. header("Pragma: no-cache");
  570. }
  571. /**
  572. * @deprecated
  573. * @see Controller::set
  574. */
  575. function _setTitle($pageTitle) {
  576. trigger_error(__('Deprecated: Use Controller::set("title", "...") instead'), E_USER_WARNING);
  577. $this->pageTitle = $pageTitle;
  578. }
  579. /**
  580. * Shows a message to the user $time seconds, then redirects to $url
  581. * Uses flash.thtml as a layout for the messages
  582. *
  583. * @param string $message Message to display to the user
  584. * @param string $url Relative URL to redirect to after the time expires
  585. * @param int $time Time to show the message
  586. */
  587. function flash($message, $url, $pause = 1) {
  588. $this->autoRender = false;
  589. $this->autoLayout = false;
  590. $this->set('url', Router::url($url));
  591. $this->set('message', $message);
  592. $this->set('pause', $pause);
  593. $this->set('page_title', $message);
  594. if (file_exists(VIEWS . 'layouts' . DS . 'flash.ctp')) {
  595. $flash = VIEWS . 'layouts' . DS . 'flash.ctp';
  596. } elseif (file_exists(VIEWS . 'layouts' . DS . 'flash.thtml')) {
  597. $flash = VIEWS . 'layouts' . DS . 'flash.thtml';
  598. } elseif ($flash = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . "layouts" . DS . 'flash.ctp')) {
  599. }
  600. $this->render(null, false, $flash);
  601. }
  602. /**
  603. * This function creates a $fieldNames array for the view to use.
  604. * @todo Map more database field types to html form fields.
  605. * @todo View the database field types from all the supported databases.
  606. *
  607. */
  608. function generateFieldNames($data = null, $doCreateOptions = true) {
  609. $fieldNames = array();
  610. $model = $this->modelClass;
  611. $modelKey = $this->modelKey;
  612. $modelObj =& ClassRegistry::getObject($modelKey);
  613. foreach($modelObj->_tableInfo->value as $column) {
  614. if ($modelObj->isForeignKey($column['name'])) {
  615. foreach($modelObj->belongsTo as $associationName => $assoc) {
  616. if($column['name'] == $assoc['foreignKey']) {
  617. $fkNames = $modelObj->keyToTable[$column['name']];
  618. $fieldNames[$column['name']]['table'] = $fkNames[0];
  619. $fieldNames[$column['name']]['label'] = Inflector::humanize($associationName);
  620. $fieldNames[$column['name']]['prompt'] = $fieldNames[$column['name']]['label'];
  621. $fieldNames[$column['name']]['model'] = Inflector::classify($associationName);
  622. $fieldNames[$column['name']]['modelKey'] = Inflector::underscore($modelObj->tableToModel[$fieldNames[$column['name']]['table']]);
  623. $fieldNames[$column['name']]['controller'] = Inflector::pluralize($fieldNames[$column['name']]['modelKey']);
  624. $fieldNames[$column['name']]['foreignKey'] = true;
  625. break;
  626. }
  627. }
  628. } else {
  629. $fieldNames[$column['name']]['label'] = Inflector::humanize($column['name']);
  630. $fieldNames[$column['name']]['prompt'] = $fieldNames[$column['name']]['label'];
  631. }
  632. $fieldNames[$column['name']]['tagName'] = $model . '/' . $column['name'];
  633. $fieldNames[$column['name']]['name'] = $column['name'];
  634. $fieldNames[$column['name']]['class'] = 'optional';
  635. $validationFields = $modelObj->validate;
  636. if (isset($validationFields[$column['name']])) {
  637. if (VALID_NOT_EMPTY == $validationFields[$column['name']]) {
  638. $fieldNames[$column['name']]['required'] = true;
  639. $fieldNames[$column['name']]['class'] = 'required';
  640. $fieldNames[$column['name']]['error'] = "Required Field";
  641. }
  642. }
  643. $lParenPos = strpos($column['type'], '(');
  644. $rParenPos = strpos($column['type'], ')');
  645. if (false != $lParenPos) {
  646. $type = substr($column['type'], 0, $lParenPos);
  647. $fieldLength = substr($column['type'], $lParenPos + 1, $rParenPos - $lParenPos - 1);
  648. } else {
  649. $type = $column['type'];
  650. }
  651. switch($type) {
  652. case "text":
  653. $fieldNames[$column['name']]['type'] = 'textarea';
  654. $fieldNames[$column['name']]['cols'] = '30';
  655. $fieldNames[$column['name']]['rows'] = '10';
  656. break;
  657. case "string":
  658. if (isset($fieldNames[$column['name']]['foreignKey'])) {
  659. $fieldNames[$column['name']]['type'] = 'select';
  660. $fieldNames[$column['name']]['options'] = array();
  661. $otherModelObj =& ClassRegistry::getObject($fieldNames[$column['name']]['modelKey']);
  662. if (is_object($otherModelObj)) {
  663. if ($doCreateOptions) {
  664. $fieldNames[$column['name']]['options'] = $otherModelObj->generateList();
  665. }
  666. $fieldNames[$column['name']]['selected'] = $data[$model][$column['name']];
  667. }
  668. } else {
  669. $fieldNames[$column['name']]['type'] = 'text';
  670. }
  671. break;
  672. case "boolean":
  673. $fieldNames[$column['name']]['type'] = 'checkbox';
  674. break;
  675. case "integer":
  676. case "float":
  677. if (strcmp($column['name'], $this->$model->primaryKey) == 0) {
  678. $fieldNames[$column['name']]['type'] = 'hidden';
  679. } else if(isset($fieldNames[$column['name']]['foreignKey'])) {
  680. $fieldNames[$column['name']]['type'] = 'select';
  681. $fieldNames[$column['name']]['options'] = array();
  682. $otherModelObj =& ClassRegistry::getObject($fieldNames[$column['name']]['modelKey']);
  683. if (is_object($otherModelObj)) {
  684. if ($doCreateOptions) {
  685. $fieldNames[$column['name']]['options'] = $otherModelObj->generateList();
  686. }
  687. $fieldNames[$column['name']]['selected'] = $data[$model][$column['name']];
  688. }
  689. } else {
  690. $fieldNames[$column['name']]['type'] = 'text';
  691. }
  692. break;
  693. case "enum":
  694. $fieldNames[$column['name']]['type'] = 'select';
  695. $fieldNames[$column['name']]['options'] = array();
  696. $enumValues = split(',', $fieldLength);
  697. foreach($enumValues as $enum) {
  698. $enum = trim($enum, "'");
  699. $fieldNames[$column['name']]['options'][$enum] = $enum;
  700. }
  701. $fieldNames[$column['name']]['selected'] = $data[$model][$column['name']];
  702. break;
  703. case "date":
  704. case "datetime":
  705. case "time":
  706. case "year":
  707. if (0 != strncmp("created", $column['name'], 7) && 0 != strncmp("modified", $column['name'], 8) && 0 != strncmp("updated", $column['name'], 7)) {
  708. $fieldNames[$column['name']]['type'] = $type;
  709. if (isset($data[$model][$column['name']])) {
  710. $fieldNames[$column['name']]['selected'] = $data[$model][$column['name']];
  711. } else {
  712. $fieldNames[$column['name']]['selected'] = null;
  713. }
  714. } else {
  715. unset($fieldNames[$column['name']]);
  716. }
  717. break;
  718. default:
  719. break;
  720. }
  721. }
  722. foreach($modelObj->hasAndBelongsToMany as $associationName => $assocData) {
  723. $otherModelKey = Inflector::underscore($assocData['className']);
  724. $otherModelObj = &ClassRegistry::getObject($otherModelKey);
  725. if ($doCreateOptions) {
  726. $fieldNames[$otherModelKey]['model'] = $associationName;
  727. $fieldNames[$otherModelKey]['label'] = "Related " . Inflector::humanize(Inflector::pluralize($associationName));
  728. $fieldNames[$otherModelKey]['prompt'] = $fieldNames[$otherModelKey]['label'];
  729. $fieldNames[$otherModelKey]['type'] = "select";
  730. $fieldNames[$otherModelKey]['multiple'] = "multiple";
  731. $fieldNames[$otherModelKey]['tagName'] = $associationName . '/' . $associationName;
  732. $fieldNames[$otherModelKey]['name'] = $associationName;
  733. $fieldNames[$otherModelKey]['class'] = 'optional';
  734. $fieldNames[$otherModelKey]['options'] = $otherModelObj->generateList();
  735. if (isset($data[$associationName])) {
  736. $fieldNames[$otherModelKey]['selected'] = $this->_selectedArray($data[$associationName], $otherModelObj->primaryKey);
  737. }
  738. }
  739. }
  740. return $fieldNames;
  741. }
  742. /**
  743. * Converts POST'ed model data to a model conditions array, suitable for a find
  744. * or findAll Model query
  745. *
  746. * @param array $data POST'ed data organized by model and field
  747. * @param mixed $op A string containing an SQL comparison operator, or an array matching operators to fields
  748. * @param string $bool SQL boolean operator: AND, OR, XOR, etc.
  749. * @param boolean $exclusive If true, and $op is an array, fields not included in $op will not be included in the returned conditions
  750. * @return array An array of model conditions
  751. */
  752. function postConditions($data = array(), $op = null, $bool = 'AND', $exclusive = false) {
  753. if ((!is_array($data) || empty($data)) && empty($this->data)) {
  754. return null;
  755. } elseif (!empty($this->data)) {
  756. $data = $this->data;
  757. }
  758. $cond = array();
  759. if ($op === null) {
  760. $op = '';
  761. }
  762. foreach($data as $model => $fields) {
  763. foreach($fields as $field => $value) {
  764. $key = $model . '.' . $field;
  765. if (is_string($op)) {
  766. $cond[$key] = $this->__postConditionMatch($op, $value);
  767. } elseif (is_array($op)) {
  768. $opFields = array_keys($op);
  769. if (in_array($key, $opFields) || in_array($field, $opFields)) {
  770. if (in_array($key, $opFields)) {
  771. $cond[$key] = $this->__postConditionMatch($op[$key], $value);
  772. } else {
  773. $cond[$key] = $this->__postConditionMatch($op[$field], $value);
  774. }
  775. } elseif (!$exclusive) {
  776. $cond[$key] = $this->__postConditionMatch(null, $value);
  777. }
  778. }
  779. }
  780. }
  781. if ($bool != null && up($bool) != 'AND') {
  782. $cond = array($bool => $cond);
  783. }
  784. return $cond;
  785. }
  786. /**
  787. * Private method used by postConditions
  788. *
  789. */
  790. function __postConditionMatch($op, $value) {
  791. if (is_string($op)) {
  792. $op = up(trim($op));
  793. }
  794. switch($op) {
  795. case '':
  796. case '=':
  797. case null:
  798. return $value;
  799. break;
  800. case 'LIKE':
  801. return 'LIKE %' . $value . '%';
  802. break;
  803. default:
  804. return $op . ' ' . $value;
  805. break;
  806. }
  807. }
  808. /**
  809. * Cleans up the date fields of current Model.
  810. *
  811. */
  812. function cleanUpFields($modelClass = null) {
  813. if ($modelClass == null) {
  814. $modelClass = $this->modelClass;
  815. }
  816. foreach($this->{$modelClass}->_tableInfo->value as $field) {
  817. if ('date' == $field['type'] && isset($this->data[$modelClass][$field['name'] . '_year'])) {
  818. $newDate = $this->data[$modelClass][$field['name'] . '_year'] . '-';
  819. $newDate .= $this->data[$modelClass][$field['name'] . '_month'] . '-';
  820. $newDate .= $this->data[$modelClass][$field['name'] . '_day'];
  821. unset($this->data[$modelClass][$field['name'] . '_year']);
  822. unset($this->data[$modelClass][$field['name'] . '_month']);
  823. unset($this->data[$modelClass][$field['name'] . '_day']);
  824. unset($this->data[$modelClass][$field['name'] . '_hour']);
  825. unset($this->data[$modelClass][$field['name'] . '_min']);
  826. unset($this->data[$modelClass][$field['name'] . '_meridian']);
  827. $this->data[$modelClass][$field['name']] = $newDate;
  828. $this->data[$modelClass][$field['name']] = $newDate;
  829. } elseif('datetime' == $field['type'] && isset($this->data[$modelClass][$field['name'] . '_year'])) {
  830. $hour = $this->data[$modelClass][$field['name'] . '_hour'];
  831. if ($hour != 12 && (isset($this->data[$modelClass][$field['name'] . '_meridian']) && 'pm' == $this->data[$modelClass][$field['name'] . '_meridian'])) {
  832. $hour = $hour + 12;
  833. }
  834. $newDate = $this->data[$modelClass][$field['name'] . '_year'] . '-';
  835. $newDate .= $this->data[$modelClass][$field['name'] . '_month'] . '-';
  836. $newDate .= $this->data[$modelClass][$field['name'] . '_day'] . ' ';
  837. $newDate .= $hour . ':' . $this->data[$modelClass][$field['name'] . '_min'] . ':00';
  838. unset($this->data[$modelClass][$field['name'] . '_year']);
  839. unset($this->data[$modelClass][$field['name'] . '_month']);
  840. unset($this->data[$modelClass][$field['name'] . '_day']);
  841. unset($this->data[$modelClass][$field['name'] . '_hour']);
  842. unset($this->data[$modelClass][$field['name'] . '_min']);
  843. unset($this->data[$modelClass][$field['name'] . '_meridian']);
  844. $this->data[$modelClass][$field['name']] = $newDate;
  845. $this->data[$modelClass][$field['name']] = $newDate;
  846. } elseif('time' == $field['type'] && isset($this->data[$modelClass][$field['name'] . '_hour'])) {
  847. $hour = $this->data[$modelClass][$field['name'] . '_hour'];
  848. if ($hour != 12 && (isset($this->data[$modelClass][$field['name'] . '_meridian']) && 'pm' == $this->data[$modelClass][$field['name'] . '_meridian'])) {
  849. $hour = $hour + 12;
  850. }
  851. $newDate = $hour . ':' . $this->data[$modelClass][$field['name'] . '_min'] . ':00';
  852. unset($this->data[$modelClass][$field['name'] . '_hour']);
  853. unset($this->data[$modelClass][$field['name'] . '_min']);
  854. unset($this->data[$modelClass][$field['name'] . '_meridian']);
  855. $this->data[$modelClass][$field['name']] = $newDate;
  856. $this->data[$modelClass][$field['name']] = $newDate;
  857. }
  858. }
  859. }
  860. /**
  861. * Handles automatic pagination of model records
  862. *
  863. * @param mixed $object
  864. * @param mixed $scope
  865. * @param array $whitelist
  866. * @return array Model query results
  867. */
  868. function paginate($object = null, $scope = array(), $whitelist = array()) {
  869. if (is_array($object)) {
  870. $whitelist = $scope;
  871. $scope = $object;
  872. $object = null;
  873. }
  874. if (is_string($object)) {
  875. if (isset($this->{$object})) {
  876. $object = $this->{$object};
  877. } elseif (isset($this->{$this->modelClass}) && isset($this->{$this->modelClass}->{$object})) {
  878. $object = $this->{$this->modelClass}->{$object};
  879. } elseif (!empty($this->uses)) {
  880. for ($i = 0; $i < count($this->uses); $i++) {
  881. $model = $this->uses[$i];
  882. if (isset($this->{$model}->{$object})) {
  883. $object = $this->{$model}->{$object};
  884. break;
  885. }
  886. }
  887. }
  888. } elseif (empty($object) || $object == null) {
  889. if (isset($this->{$this->modelClass})) {
  890. $object = $this->{$this->modelClass};
  891. } else {
  892. $object = $this->{$this->uses[0]};
  893. }
  894. }
  895. if (!is_object($object)) {
  896. // Error: can't find object
  897. return array();
  898. }
  899. $options = am($this->params, $this->params['url'], $this->passedArgs);
  900. if (isset($this->paginate[$object->name])) {
  901. $defaults = $this->paginate[$object->name];
  902. } else {
  903. $defaults = $this->paginate;
  904. }
  905. if (isset($options['show'])) {
  906. $options['limit'] = $options['show'];
  907. }
  908. if (isset($options['sort']) && isset($options['direction'])) {
  909. $options['order'] = array($options['sort'] => $options['direction']);
  910. } elseif (isset($options['sort'])) {
  911. $options['order'] = array($options['sort'] => 'asc');
  912. }
  913. if (!empty($options['order']) && is_array($options['order'])) {
  914. $key = key($options['order']);
  915. if (strpos($key, '.') === false && $object->hasField($key)) {
  916. $options['order'][$object->name . '.' . $key] = $options['order'][$key];
  917. unset($options['order'][$key]);
  918. }
  919. }
  920. $vars = array('fields', 'order', 'limit', 'page', 'recursive');
  921. $keys = array_keys($options);
  922. $count = count($keys);
  923. for($i = 0; $i < $count; $i++) {
  924. if (!in_array($keys[$i], $vars)) {
  925. unset($options[$keys[$i]]);
  926. }
  927. if (empty($whitelist) && ($keys[$i] == 'fields' || $keys[$i] == 'recursive')) {
  928. unset($options[$keys[$i]]);
  929. } elseif (!empty($whitelist) && !in_array($keys[$i], $whitelist)) {
  930. unset($options[$keys[$i]]);
  931. }
  932. }
  933. $conditions = $fields = $order = $limit = $page = $recursive = null;
  934. $options = am($defaults, $options);
  935. if (isset($this->paginate[$object->name])) {
  936. $defaults = $this->paginate[$object->name];
  937. } else {
  938. $defaults = $this->paginate;
  939. }
  940. if (!isset($defaults['conditions'])) {
  941. $defaults['conditions'] = array();
  942. }
  943. extract(am(array('page' => 1, 'limit' => 20), $defaults, $options));
  944. if (is_array($scope) && !empty($scope)) {
  945. $conditions = am($conditions, $scope);
  946. } elseif (is_string($scope)) {
  947. $conditions = array($conditions, $scope);
  948. }
  949. $results = $object->findAll($conditions, $fields, $order, $limit, $page, $recursive);
  950. $count = $object->findCount($conditions);
  951. $paging = array(
  952. 'page' => $page,
  953. 'current' => count($results),
  954. 'count' => $count,
  955. 'prevPage' => ($page > 1),
  956. 'nextPage' => ($count > ($page * $limit)),
  957. 'pageCount' => ceil($count / $limit),
  958. 'defaults' => am(array('limit' => 20, 'step' => 1), $defaults),
  959. 'options' => $options
  960. );
  961. $this->params['paging'][$object->name] = $paging;
  962. if (!in_array('Paginator', $this->helpers) && !array_key_exists('Paginator', $this->helpers)) {
  963. $this->helpers[] = 'Paginator';
  964. }
  965. return $results;
  966. }
  967. /**
  968. * Called before the controller action. Overridden in subclasses.
  969. *
  970. */
  971. function beforeFilter() {
  972. }
  973. /**
  974. * Called after the controller action is run, but before the view is rendered. Overridden in subclasses.
  975. *
  976. */
  977. function beforeRender() {
  978. }
  979. /**
  980. * Called after the controller action is run and rendered. Overridden in subclasses.
  981. *
  982. */
  983. function afterFilter() {
  984. }
  985. /**
  986. * This method should be overridden in child classes.
  987. *
  988. * @param string $method name of method called example index, edit, etc.
  989. * @return boolean
  990. */
  991. function _beforeScaffold($method) {
  992. return true;
  993. }
  994. /**
  995. * This method should be overridden in child classes.
  996. *
  997. * @param string $method name of method called either edit or update.
  998. * @return boolean
  999. */
  1000. function _afterScaffoldSave($method) {
  1001. return true;
  1002. }
  1003. /**
  1004. * This method should be overridden in child classes.
  1005. *
  1006. * @param string $method name of method called either edit or update.
  1007. * @return boolean
  1008. */
  1009. function _afterScaffoldSaveError($method) {
  1010. return true;
  1011. }
  1012. /**
  1013. * This method should be overridden in child classes.
  1014. * If not it will render a scaffold error.
  1015. * Method MUST return true in child classes
  1016. *
  1017. * @param string $method name of method called example index, edit, etc.
  1018. * @return boolean
  1019. */
  1020. function _scaffoldError($method) {
  1021. return false;
  1022. }
  1023. /**
  1024. * Enter description here...
  1025. *
  1026. * @param unknown_type $data
  1027. * @param unknown_type $key
  1028. * @return unknown
  1029. */
  1030. function _selectedArray($data, $key = 'id') {
  1031. if(!is_array($data)) {
  1032. $model = $data;
  1033. if(!empty($this->data[$model][$model])) {
  1034. return $this->data[$model][$model];
  1035. }
  1036. if(!empty($this->data[$model])) {
  1037. $data = $this->data[$model];
  1038. }
  1039. }
  1040. $array = array();
  1041. if(!empty($data)) {
  1042. foreach($data as $var) {
  1043. $array[$var[$key]] = $var[$key];
  1044. }
  1045. }
  1046. return $array;
  1047. }
  1048. }
  1049. ?>