PageRenderTime 34ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Core/Routes/Model/Route.php

http://github.com/infinitas/infinitas
PHP | 391 lines | 257 code | 41 blank | 93 comment | 24 complexity | 4c505edb3d48bcf32bfd4f085fb7cd3a MD5 | raw file
  1. <?php
  2. /**
  3. * Route
  4. *
  5. * @package Infinitas.Routes.Model
  6. */
  7. /**
  8. * Filemanager Events
  9. *
  10. * The events that can be triggered for the events class.
  11. *
  12. * @copyright Copyright (c) 2010 Carl Sutton ( dogmatic69 )
  13. * @link http://www.infinitas-cms.org
  14. * @package Infinitas.Routes.Model
  15. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  16. * @since 0.5a
  17. *
  18. * @author Carl Sutton <dogmatic69@infinitas-cms.org>
  19. */
  20. class Route extends RoutesAppModel {
  21. /**
  22. * belongs to relations
  23. *
  24. * @var array
  25. */
  26. public $belongsTo = array(
  27. 'Theme' => array(
  28. 'className' => 'Themes.Theme',
  29. 'fields' => array(
  30. 'Theme.id',
  31. 'Theme.name',
  32. 'Theme.default_layout'
  33. )
  34. )
  35. );
  36. /**
  37. * Constructor
  38. *
  39. * @param type $id
  40. * @param type $table
  41. * @param type $ds
  42. *
  43. * @return void
  44. */
  45. public function __construct($id = false, $table = null, $ds = null) {
  46. parent::__construct($id, $table, $ds);
  47. $this->order = array(
  48. $this->alias . '.ordering' => 'ASC'
  49. );
  50. $this->validate = array(
  51. 'name' => array(
  52. 'notEmpty' => array(
  53. 'rule' => 'notEmpty',
  54. 'message' => __d('routes', 'Please enter a name for this route'),
  55. 'required' => true,
  56. 'on' => 'create'
  57. ),
  58. 'isUnique' => array(
  59. 'rule' => 'isUnique',
  60. 'message' => __d('routes', 'There is already a route with this name')
  61. )
  62. ),
  63. 'url' => array(
  64. 'validUrl' => array(
  65. 'required' => true,
  66. 'rule' => 'validateUrlOrAbsolute',
  67. 'message' => __d('routes', 'Please use a valid url (absolute or full)')
  68. ),
  69. 'isUnique' => array(
  70. 'rule' => 'isUnique',
  71. 'message' => __d('routes', 'There is already a route for this url')
  72. )
  73. ),
  74. 'plugin' => array(
  75. 'notEmpty' => array(
  76. 'required' => true,
  77. 'rule' => 'notEmpty',
  78. 'message' => __d('routes', 'Please select where this route will go')
  79. ),
  80. 'validatePluginExists' => array(
  81. 'rule' => array('validatePluginExists', array('pluginType' => 'installed')),
  82. 'message' => __d('routes', 'Please select a valid controller')
  83. )
  84. ),
  85. 'controller' => array(
  86. 'validateControllerExists' => array(
  87. 'required' => true,
  88. 'rule' => array('validateControllerExists', array('pluginField' => 'plugin')),
  89. 'message' => __d('routes', 'Please select a valid controller')
  90. )
  91. ),
  92. 'action' => array(
  93. 'validateActionExists' => array(
  94. 'required' => true,
  95. 'rule' => array('validateActionExists', array('pluginField' => 'plugin', 'controllerField' => 'controller')),
  96. 'message' => __d('routes', 'Please select a valid action')
  97. )
  98. ),
  99. 'values' => array(
  100. 'validateJson' => array(
  101. 'allowEmpty' => true,
  102. 'rule' => 'validateJson',
  103. 'message' => __d('routes', 'Please enter valid configuration (json) for the route or leave blank')
  104. )
  105. ),
  106. 'rules' => array(
  107. 'validateJson' => array(
  108. 'allowEmpty' => true,
  109. 'rule' => 'validateJson',
  110. 'message' => __d('routes', 'Please enter valid rules (json) for the route or leave blank')
  111. )
  112. ),
  113. 'force_frontend' => array(
  114. 'validateEitherOr' => array(
  115. 'allowEmpty' => true,
  116. 'rule' => array('validateEitherOr', array('force_backend', 'force_frontend')),
  117. 'message' => __d('routes', 'Please select either frontend or backend')
  118. )
  119. ),
  120. 'force_backend' => array(
  121. 'validateEitherOr' => array(
  122. 'allowEmpty' => true,
  123. 'rule' => array('validateEitherOr', array('force_backend', 'force_frontend')),
  124. 'message' => __d('routes', 'Please select either frontend or backend')
  125. )
  126. ),
  127. 'pass' => array(
  128. 'custom' => array(
  129. 'rule' => '/^([a-z]+|\b,\b)+$/',
  130. 'message' => __d('routes', 'Please enter a comma seperated list of variables to pass, no spaces'),
  131. 'allowEmpty' => true
  132. )
  133. )
  134. );
  135. }
  136. /**
  137. * beforeValidate callback
  138. *
  139. * Set force_backend/frontend to null if it is 0 so that allowEmpty will be used for non checked boxes.
  140. *
  141. * @param array $options the validation options
  142. *
  143. * @return array
  144. */
  145. public function beforeValidate($options = array()) {
  146. if (array_key_exists('force_backend', $this->data[$this->alias]) && !$this->data[$this->alias]['force_backend']) {
  147. unset($this->data[$this->alias]['force_backend']);
  148. }
  149. if (array_key_exists('force_frontend', $this->data[$this->alias]) && !$this->data[$this->alias]['force_frontend']) {
  150. unset($this->data[$this->alias]['force_frontend']);
  151. }
  152. return parent::beforeValidate($options);
  153. }
  154. /**
  155. * BeforeSave callback
  156. *
  157. * Sort out the plugin name before saving
  158. *
  159. * @param array $options
  160. *
  161. * @return boolean
  162. */
  163. public function beforeSave($options = array()) {
  164. parent::beforeSave($options);
  165. if (!empty($this->data[$this->alias]['plugin'])) {
  166. $this->data[$this->alias]['plugin'] = Inflector::underscore($this->data[$this->alias]['plugin']);
  167. }
  168. if (!empty($this->data[$this->alias]['controller'])) {
  169. $this->data[$this->alias]['controller'] = str_replace('_controller', '', Inflector::underscore($this->data[$this->alias]['controller']));
  170. }
  171. return true;
  172. }
  173. /**
  174. * AfterFind callback
  175. *
  176. * After finding routes fix up the plugin names
  177. *
  178. * @param array $results
  179. * @param boolean $primary
  180. *
  181. * @return string
  182. */
  183. public function afterFind($results, $primary = false) {
  184. $results = parent::afterFind($results, $primary);
  185. if ($this->findQueryType == 'first' && !empty($results[0][$this->alias][$this->primaryKey])) {
  186. $results[0][$this->alias]['plugin'] = Inflector::camelize($results[0][$this->alias]['plugin']);
  187. $results[0][$this->alias]['controller'] = Inflector::camelize($results[0][$this->alias]['controller']) . 'Controller';
  188. }
  189. return $results;
  190. }
  191. /**
  192. * Get all routes required for the app
  193. *
  194. * Gets and formats the routes data and returns it ready for InfinitasRouter::connect()
  195. * only active routes are needed.
  196. *
  197. * A cache is also created of the params needed in to build a url so that
  198. * the onSlugUrl events are able to detect the type of url that is needed
  199. * and build them automatically.
  200. *
  201. * @return array
  202. */
  203. public function getRoutes() {
  204. $routes = false; //Cache::read('routes', 'routes');
  205. if ($routes !== false) {
  206. return $routes;
  207. }
  208. $config = array(
  209. 'fields' => array(
  210. $this->alias . '.url',
  211. $this->alias . '.prefix',
  212. $this->alias . '.plugin',
  213. $this->alias . '.controller',
  214. $this->alias . '.action',
  215. $this->alias . '.values',
  216. $this->alias . '.pass',
  217. $this->alias . '.rules',
  218. $this->alias . '.force_backend',
  219. $this->alias . '.force_frontend',
  220. $this->alias . '.theme_id',
  221. $this->alias . '.layout',
  222. $this->Theme->alias . '.' . $this->Theme->primaryKey,
  223. $this->Theme->alias . '.' . $this->Theme->displayField,
  224. $this->Theme->alias . '.default_layout',
  225. ),
  226. 'conditions' => array(
  227. $this->alias . '.active' => 1
  228. ),
  229. 'order' => array(
  230. $this->alias . '.ordering' => 'ASC'
  231. ),
  232. 'joins' => array(
  233. array(
  234. 'table' => $this->Theme->tablePrefix . $this->Theme->useTable,
  235. 'alias' => $this->Theme->alias,
  236. 'type' => 'LEFT',
  237. 'conditions' => array(
  238. sprintf(
  239. '%s.%s = %s.%s',
  240. $this->alias, $this->belongsTo[$this->Theme->alias]['foreignKey'],
  241. $this->Theme->alias, $this->Theme->primaryKey
  242. )
  243. )
  244. )
  245. )
  246. );
  247. try {
  248. $routes = $this->find('all', $config);
  249. }
  250. catch(Exception $e) {
  251. CakeLog::write('infinitas', $e->getMessage());
  252. return array();
  253. }
  254. $config = array();
  255. $routingRules = array();
  256. foreach ($routes as $array) {
  257. $vaules = $regex = array();
  258. $routingRules[][$this->alias] = array(
  259. 'url' => $array[$this->alias]['url'],
  260. 'values' => $this->getValues($array[$this->alias]),
  261. 'regex' => $this->getRegex($array[$this->alias]['rules'], $array[$this->alias]['pass']),
  262. 'theme' => $array[$this->Theme->alias]['name'],
  263. 'layout' => !empty($array[$this->alias]['layout']) ? $array[$this->alias]['layout'] : $array[$this->Theme->alias]['default_layout'],
  264. );
  265. if (!strstr($array[$this->alias]['url'], ':')) {
  266. continue;
  267. }
  268. $array = $array[$this->alias];
  269. $params = array();
  270. foreach (explode('/', $array['url']) as $param) {
  271. if (!strstr($param, ':')) {
  272. continue;
  273. }
  274. foreach (array_filter(explode(':', $param)) as $part) {
  275. $params[] = trim($part, ' -');
  276. }
  277. }
  278. $array['plugin'] = !empty($array['plugin']) ? $array['plugin'] : '__APP__';
  279. if ($array['prefix']) {
  280. $config[Inflector::camelize($array['plugin'])][$array['controller']][$array['prefix']][$array['action']][$array['url']] = $params;
  281. }
  282. else{
  283. $config[Inflector::camelize($array['plugin'])][$array['controller']][$array['action']][$array['url']] = $params;
  284. }
  285. }
  286. unset($routes);
  287. Cache::write('routes', $routingRules, 'routes');
  288. Configure::write('Routing.lookup', $config);
  289. return $routingRules;
  290. }
  291. /**
  292. * get values for the route
  293. *
  294. * gets the values that are in the route and creates an array of what is
  295. * set for Router::connect
  296. *
  297. * @param array $route the route from the database
  298. *
  299. * @return array
  300. */
  301. public function getValues($route = array()) {
  302. if (!$route) {
  303. return false;
  304. }
  305. $values = array();
  306. if (!empty($route['prefix'])) {
  307. $values['prefix'] = $route['prefix'];
  308. }
  309. if (!empty($route['plugin'])) {
  310. $values['plugin'] = $route['plugin'];
  311. }
  312. if (!empty($route['controller'])) {
  313. $values['controller'] = $route['controller'];
  314. }
  315. if (!empty($route['action'])) {
  316. $values['action'] = $route['action'];
  317. }
  318. if (!empty($route['values'])) {
  319. $values = array_merge($values, $this->singleDimentionArray($this->getJson($route['values'])));
  320. }
  321. if ($route['force_backend']) {
  322. $values['admin'] = true;
  323. }
  324. else if ($route['force_frontend']) {
  325. $values['admin'] = null;
  326. }
  327. return $values;
  328. }
  329. /**
  330. * get the regex rules
  331. *
  332. * gets the json regex rules from the data and creates an array or
  333. * returns an empty array.
  334. *
  335. * @param array $field the data from the rute
  336. * @param string $pass array of fields to pass back to the controller
  337. *
  338. * @return array
  339. */
  340. public function getRegex($field, $pass = null) {
  341. $values = array();
  342. if (!empty($field)) {
  343. $values = $this->singleDimentionArray($this->getJson($field));
  344. }
  345. if ($pass) {
  346. $values['pass'] = explode(',', $pass);
  347. }
  348. return $values;
  349. }
  350. }