PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/manager/modules/lightvc.php

http://flextrine2.googlecode.com/
PHP | 1424 lines | 588 code | 123 blank | 713 comment | 79 complexity | e029da0f65e5c891a8058fe474328ccf MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * LightVC - A lightweight view-controller framework.
  4. * http://lightvc.org/
  5. *
  6. * You provide your own model/ORM. We recommend Cough <http://coughphp.com>.
  7. *
  8. * The purpose of this framework is to provide just a "view-controller"
  9. * setup without all the other junk. Ideally, the classes from other frameworks
  10. * should be reusable but instead they are mostly coupled with their frameworks.
  11. * It's up to you to go get those classes if you need them, or provide your own.
  12. *
  13. * Additionally, we've decoupled it from any sort of Model so that you can use
  14. * the one you already know and love. And if you don't know one, now is a great
  15. * time to check out CoughPHP. Other ORMs can be found at:
  16. *
  17. * http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#PHP
  18. *
  19. * By providing just the VC, we increase the reusability of not only the
  20. * framework itself, but non-framework components as well.
  21. *
  22. * The framework is fast. Currently the speed of this framework is unmatched by
  23. * any other PHP framework available today.
  24. *
  25. * You get to use the classes you've already been using without worrying about
  26. * naming conflicts or inefficiencies from loading both your classes and the
  27. * classes from some other framework.
  28. *
  29. * LightVC aims to be easier to use, more configurable, and light in footprint.
  30. *
  31. * @author Anthony Bush
  32. * @version 1.0.4 (2008-03-15)
  33. * @package lightvc
  34. * @see http://lightvc.org/
  35. **/
  36. /**
  37. * Configuration class for the LVC suite of classes.
  38. *
  39. * @package lightvc
  40. * @author Anthony Bush
  41. * @since 2007-04-20
  42. **/
  43. class Lvc_Config {
  44. protected static $controllerPaths = array();
  45. protected static $controllerSuffix = '.php'; // e.g. _controller.php
  46. protected static $controllerViewPaths = array();
  47. protected static $controllerViewSuffix = '.php'; // e.g. .tpl.php
  48. protected static $layoutViewPaths = array();
  49. protected static $layoutViewSuffix = '.php'; // e.g. .tpl.php
  50. protected static $elementViewPaths = array();
  51. protected static $elementViewSuffix = '.php'; // e.g. .tpl.php
  52. protected static $viewClassName = 'Lvc_View'; // e.g. AppView
  53. protected static $layoutContentVarName = 'layoutContent'; // e.g. content_for_layout
  54. /**
  55. * Sets whether or not to send action params as an array or as arguments
  56. * to the function.
  57. *
  58. * true => action($params)
  59. * false => action($param1, $param2, $param3, ...)
  60. *
  61. * @var boolean
  62. **/
  63. protected static $sendActionParamsAsArray = false;
  64. // These may be moved into some sort of routing thing later. For now:
  65. /**
  66. * The controller name to use if no controller name can be gathered from the request.
  67. *
  68. * @var string
  69. **/
  70. protected static $defaultControllerName = 'page';
  71. /**
  72. * The action name to call on the defaultControllerName if no controller name can be gathered from the request.
  73. *
  74. * @var string
  75. **/
  76. protected static $defaultControllerActionName = 'view';
  77. /**
  78. * The action params to use when calling defaultControllerActionName if no controller name can be gathered from the request.
  79. *
  80. * @var string
  81. **/
  82. protected static $defaultControllerActionParams = array('page_name' => 'home');
  83. /**
  84. * The default action name to call on a controller if the controller name
  85. * was gathered from the request, but the action name couldn't be.
  86. *
  87. * @var string
  88. **/
  89. protected static $defaultActionName = 'index';
  90. // Configuration Methods
  91. public static function addControllerPath($path) {
  92. self::$controllerPaths[] = $path;
  93. }
  94. public static function setControllerSuffix($suffix) {
  95. self::$controllerSuffix = $suffix;
  96. }
  97. public static function addControllerViewPath($path) {
  98. self::$controllerViewPaths[] = $path;
  99. }
  100. public static function setControllerViewSuffix($suffix) {
  101. self::$controllerViewSuffix = $suffix;
  102. }
  103. public static function addLayoutViewPath($path) {
  104. self::$layoutViewPaths[] = $path;
  105. }
  106. public static function setLayoutViewSuffix($suffix) {
  107. self::$layoutViewSuffix = $suffix;
  108. }
  109. public static function addElementViewPath($path) {
  110. self::$elementViewPaths[] = $path;
  111. }
  112. public static function setElementViewSuffix($suffix) {
  113. self::$elementViewSuffix = $suffix;
  114. }
  115. public static function setViewClassName($className) {
  116. self::$viewClassName = $className;
  117. }
  118. public static function setLayoutContentVarName($varName) {
  119. self::$layoutContentVarName = $varName;
  120. }
  121. public static function getLayoutContentVarName() {
  122. return self::$layoutContentVarName;
  123. }
  124. public static function setSendActionParamsAsArray($bool) {
  125. self::$sendActionParamsAsArray = $bool;
  126. }
  127. public static function getSendActionParamsAsArray() {
  128. return self::$sendActionParamsAsArray;
  129. }
  130. public static function setDefaultControllerName($defaultControllerName) {
  131. self::$defaultControllerName = $defaultControllerName;
  132. }
  133. public static function setDefaultControllerActionName($defaultControllerActionName) {
  134. self::$defaultControllerActionName = $defaultControllerActionName;
  135. }
  136. public static function setDefaultControllerActionParams($defaultControllerActionParams) {
  137. self::$defaultControllerActionParams = $defaultControllerActionParams;
  138. }
  139. public static function setDefaultActionName($defaultActionName) {
  140. self::$defaultActionName = $defaultActionName;
  141. }
  142. public static function getDefaultControllerName() {
  143. return self::$defaultControllerName;
  144. }
  145. public static function getDefaultControllerActionName() {
  146. return self::$defaultControllerActionName;
  147. }
  148. public static function getDefaultControllerActionParams() {
  149. return self::$defaultControllerActionParams;
  150. }
  151. public static function getDefaultActionName() {
  152. return self::$defaultActionName;
  153. }
  154. // Retrieval Methods
  155. public static function getController($controllerName) {
  156. foreach (self::$controllerPaths as $path) {
  157. $file = $path . $controllerName . self::$controllerSuffix;
  158. if (file_exists($file)) {
  159. include_once($file);
  160. $controllerClass = self::getControllerClassName($controllerName);
  161. $controller = new $controllerClass();
  162. $controller->setControllerName($controllerName);
  163. return $controller;
  164. }
  165. }
  166. return null;
  167. }
  168. public static function getControllerClassName($controllerName) {
  169. return str_replace(' ', '', ucwords(str_replace('_', ' ', $controllerName))) . 'Controller';
  170. }
  171. public static function getActionFunctionName($actionName) {
  172. return 'action' . str_replace(' ', '', ucwords(str_replace('_', ' ', $actionName)));
  173. }
  174. public static function getControllerView($viewName, &$data = array()) {
  175. return self::getView($viewName, $data, self::$controllerViewPaths, self::$controllerViewSuffix);
  176. }
  177. public static function getElementView($elementName, &$data = array()) {
  178. return self::getView($elementName, $data, self::$elementViewPaths, self::$elementViewSuffix);
  179. }
  180. public static function getLayoutView($layoutName, &$data = array()) {
  181. return self::getView($layoutName, $data, self::$layoutViewPaths, self::$layoutViewSuffix);
  182. }
  183. /**
  184. * As an Lvc developer, you'll probably want to use `getControllerView`,
  185. * `getElementView`, or `getLayoutView`.
  186. *
  187. * Example usage:
  188. *
  189. * // Pass the whole file name and leave off the last parameters
  190. * getView('/full/path/to/file/file.php', $data);
  191. *
  192. * // Pass the view name and specify the paths to scan and the suffix to append.
  193. * getView('file', $data, array('/full/path/to/file/'), '.php');
  194. *
  195. * @var mixed Lvc_View object if one is found, otherwise null.
  196. * @see getControllerView(), getElementView(), getLayoutView(), Lvc_Config::setViewClassName()
  197. **/
  198. public static function getView($viewName, &$data = array(), &$paths = array(''), $suffix = '') {
  199. foreach ($paths as $path) {
  200. $file = $path . $viewName . $suffix;
  201. if (file_exists($file)) {
  202. return new self::$viewClassName($file, $data);
  203. }
  204. }
  205. return null;
  206. }
  207. public static function dump() {
  208. echo '<pre>';
  209. echo '<strong>Controller Paths:</strong>' . "\n";
  210. print_r(self::$controllerPaths);
  211. echo '<strong>Controller Suffix:</strong> ' . self::$controllerSuffix . "\n\n";
  212. echo '<strong>Layout View Paths:</strong>' . "\n";
  213. print_r(self::$layoutViewPaths);
  214. echo '<strong>Layout View Suffix:</strong> ' . self::$layoutViewSuffix . "\n\n";
  215. echo '<strong>Controller View Paths:</strong>' . "\n";
  216. print_r(self::$controllerViewPaths);
  217. echo '<strong>Controller View Suffix:</strong> ' . self::$controllerViewSuffix . "\n\n";
  218. echo '<strong>Element View Paths:</strong>' . "\n";
  219. print_r(self::$elementViewPaths);
  220. echo '<strong>Element View Suffix:</strong> ' . self::$elementViewSuffix . "\n\n";
  221. echo '</pre>';
  222. }
  223. }
  224. /**
  225. * Lvc classes throw this type of exception.
  226. *
  227. * @package lightvc
  228. * @author Anthony Bush
  229. * @since 2007-04-20
  230. **/
  231. class Lvc_Exception extends Exception {
  232. }
  233. /**
  234. * A request provides information about what controller and action to run and
  235. * what parameters to run them with.
  236. *
  237. * @package lightvc
  238. * @author Anthony Bush
  239. * @since 2007-04-20
  240. **/
  241. class Lvc_Request {
  242. protected $controllerName = '';
  243. protected $controllerParams = array();
  244. protected $actionName = '';
  245. protected $actionParams = array();
  246. public function getControllerName() {
  247. return $this->controllerName;
  248. }
  249. public function &getControllerParams() {
  250. return $this->controllerParams;
  251. }
  252. public function getActionName() {
  253. return $this->actionName;
  254. }
  255. public function &getActionParams() {
  256. return $this->actionParams;
  257. }
  258. public function setControllerName($controllerName) {
  259. $this->controllerName = $controllerName;
  260. }
  261. public function setControllerParams(&$controllerParams) {
  262. $this->controllerParams = $controllerParams;
  263. }
  264. public function setActionName($actionName) {
  265. $this->actionName = $actionName;
  266. }
  267. public function setActionParams($actionParams) {
  268. $this->actionParams = $actionParams;
  269. }
  270. /**
  271. * Override this in sub request objects to have custom error messages appended to
  272. * LightVC messages. For example, when HTTP Requests error, it might be useful
  273. * to put the requested URL in the error log with the "Unable to load controller"
  274. * message.
  275. *
  276. * @return string
  277. * @since 2008-03-14
  278. **/
  279. public function getAdditionalErrorInfo() {
  280. return '';
  281. }
  282. }
  283. /**
  284. * An HTTP request contains parameters from the GET, POST, PUT, and
  285. * DELETE arena.
  286. *
  287. * @package lightvc
  288. * @author Anthony Bush
  289. * @since 2007-04-20
  290. **/
  291. class Lvc_HttpRequest extends Lvc_Request {
  292. protected $params = array();
  293. public function __construct() {
  294. $params = array();
  295. // Save GET data
  296. if (isset($_GET)) {
  297. $params['get'] =& $_GET;
  298. } else {
  299. $params['get'] = array();
  300. }
  301. // Ensure that we have some mode_rewritten url.
  302. if (!isset($params['get']['url'])) {
  303. $params['get']['url'] = '';
  304. }
  305. // Save POST data
  306. $params['post'] =& $_POST;
  307. // Save FILE data (consilidate it with _POST data)
  308. foreach ($_FILES as $name => $data) {
  309. if ($name != 'data') {
  310. $params['post'][$name] = $data;
  311. } else {
  312. // Convert _FILE[data][key][model][field] -> [data][model][field][key]
  313. // so that it matches up with _POST "data"
  314. foreach ($data as $key => $modelData) {
  315. foreach ($modelData as $model => $fields) {
  316. foreach ($fields as $field => $value) {
  317. $params['post']['data'][$model][$field][$key] = $value;
  318. }
  319. }
  320. }
  321. }
  322. }
  323. // Set params that will be used by routers.
  324. $this->setParams($params);
  325. // An HTTP request will default to passing all the parameters to the controller.
  326. $this->setControllerParams($params);
  327. }
  328. public function &getParams() {
  329. return $this->params;
  330. }
  331. public function setParams(&$params) {
  332. $this->params = $params;
  333. }
  334. /**
  335. * Provides additional error information that might be useful when debugging
  336. * errors.
  337. *
  338. * @return string
  339. * @since 2008-03-14
  340. **/
  341. public function getAdditionalErrorInfo() {
  342. if (isset($_SERVER['REQUEST_URI'])) {
  343. return 'Request URL was ' . $_SERVER['REQUEST_URI'];
  344. } else {
  345. return parent::getAdditionalErrorInfo();
  346. }
  347. }
  348. }
  349. /**
  350. * A router interface must at least provide a route() function that takes a
  351. * request object.
  352. *
  353. * @package lightvc
  354. * @author Anthony Bush
  355. * @since 2007-04-22
  356. **/
  357. interface Lvc_RouterInterface {
  358. /**
  359. * Set the appropriate controller, action, and action parameters to use on
  360. * the request object and return true. If no appropriate controller info
  361. * can be found, return false.
  362. *
  363. * @param mixed $request A request object to route.
  364. * @return boolean
  365. * @author Anthony Bush
  366. * @since 2007-04-22
  367. **/
  368. public function route($request);
  369. }
  370. /**
  371. * Routes a request using only GET data.
  372. *
  373. * You can change the default keys for controller and action detection using
  374. * {@link setControllerKey()} and {@link setActionKey()} respectively.
  375. *
  376. * @package lightvc
  377. * @author Anthony Bush
  378. * @since 2007-04-22
  379. **/
  380. class Lvc_GetRouter implements Lvc_RouterInterface {
  381. protected $controllerKey = 'controller';
  382. protected $actionKey = 'action';
  383. protected $actionParamsKey = null;
  384. protected $routes = array();
  385. public function setControllerKey($controllerKey) {
  386. $this->controllerKey = $controllerKey;
  387. }
  388. public function setActionKey($actionKey) {
  389. $this->actionKey = $actionKey;
  390. }
  391. public function setActionParamsKey($actionParamsKey) {
  392. $this->actionParamsKey = $actionParamsKey;
  393. }
  394. /**
  395. * Add a param order for a controller / action.
  396. *
  397. * For example:
  398. *
  399. * $router->addRoute('pages', 'show_page', array('page_name'));
  400. *
  401. * will route:
  402. *
  403. * ?controller=pages&action=show_page&page_name=about
  404. *
  405. * to:
  406. *
  407. * PagesController::actionShowPage('about');
  408. *
  409. * whereas without the route the controller would be invoked with:
  410. *
  411. * PagesController::actionShowPage();
  412. *
  413. * and you'd have to access the page_name via $this->get['page_name'].
  414. *
  415. * @return void
  416. * @author Anthony Bush
  417. * @since 2007-05-10
  418. **/
  419. public function addRoute($controllerName, $actionName, $actionParamsOrder = array()) {
  420. $this->routes[$controllerName][$actionName] = $actionParamsOrder;
  421. }
  422. /**
  423. * Set all routes at once. Useful if you want to specify routes in a
  424. * config file and then pass them to this router all at once. See
  425. * {@link addRoute()} for routing specifications.
  426. *
  427. * @return void
  428. * @author Anthony Bush
  429. * @since 2007-05-10
  430. **/
  431. public function setRoutes(&$routes) {
  432. $this->routes = $routes;
  433. }
  434. /**
  435. * Construct the router and set all routes at once. See {@link setRoutes()}
  436. * for more info.
  437. *
  438. * @return void
  439. * @author Anthony Bush
  440. * @see setRoutes()
  441. * @since 2007-05-10
  442. **/
  443. public function __construct(&$routes = null) {
  444. if ( ! is_null($routes)) {
  445. $this->setRoutes($routes);
  446. }
  447. }
  448. /**
  449. * Attempts to routes a request using only the GET data.
  450. *
  451. * @param Lvc_HttpRequest $request A request object to route.
  452. * @return boolean
  453. * @author Anthony Bush
  454. * @since 2007-04-22
  455. **/
  456. public function route($request) {
  457. $params = $request->getParams();
  458. // Use GET parameters to set controller, action, and action params
  459. if (isset($params['get'][$this->controllerKey])) {
  460. $request->setControllerName($params['get'][$this->controllerKey]);
  461. if (isset($params['get'][$this->actionKey])) {
  462. $request->setActionName($params['get'][$this->actionKey]);
  463. } else {
  464. $request->setActionName(Lvc_Config::getDefaultActionName());
  465. }
  466. // Using paramsKey method?
  467. if ( ! is_null($this->actionParamsKey) && isset($params['get'][$this->actionParamsKey])) {
  468. $request->setActionParams($params['get'][$this->actionParamsKey]);
  469. }
  470. // Using routes?
  471. else if ( ! empty($this->routes)) {
  472. if (isset($this->routes[$request->getControllerName()])
  473. && isset($this->routes[$request->getControllerName()][$request->getActionName()])
  474. ) {
  475. $actionParams = array();
  476. foreach ($this->routes[$request->getControllerName()][$request->getActionName()] as $paramName) {
  477. $actionParams[$paramName] = @$params['get'][$paramName];
  478. }
  479. $request->setActionParams($actionParams);
  480. }
  481. }
  482. return true;
  483. } else {
  484. return false;
  485. }
  486. }
  487. }
  488. /**
  489. * Attempts to route a request using the GET value for the 'url' key, which
  490. * should be set by the mod_rewrite rules. Any additional "directories" are
  491. * used as parameters for the action (using numeric indexes). Any extra GET
  492. * data is also amended to the action parameters.
  493. *
  494. * If you need the numeric indexes to map to specific parameter names, use
  495. * the {@link Lvc_ParamOrderRewriteRouter} instead.
  496. *
  497. * @package lightvc
  498. * @author Anthony Bush
  499. * @since 2007-04-22
  500. **/
  501. class Lvc_RewriteRouter implements Lvc_RouterInterface {
  502. /**
  503. * Attempts to route a request using the GET value for the 'url' key, which
  504. * should be set by the mod_rewrite rules. Any additional "directories" are
  505. * used as parameters for the action (using numeric indexes). Any extra GET
  506. * data is also amended to the action parameters.
  507. *
  508. * @param Lvc_HttpRequest $request A request object to route.
  509. * @return boolean
  510. * @author Anthony Bush
  511. * @since 2007-04-22
  512. **/
  513. public function route($request) {
  514. $params = $request->getParams();
  515. if (isset($params['get']['url'])) {
  516. // Use mod_rewrite's url
  517. $url = explode('/', $params['get']['url']);
  518. $count = count($url);
  519. // Set controller, action, and some action params from the segmented URL.
  520. if ($count > 0) {
  521. $request->setControllerName($url[0]);
  522. $actionParams = array();
  523. if ($count > 1) {
  524. $request->setActionName($url[1]);
  525. if ($count > 2) {
  526. for ($i = 2; $i < $count; $i++) {
  527. if ( ! empty($url[$i])) {
  528. $actionParams[] = $url[$i];
  529. }
  530. }
  531. }
  532. }
  533. $request->setActionParams($actionParams);
  534. return true;
  535. }
  536. }
  537. return false;
  538. }
  539. }
  540. /**
  541. * Routes a request using mod_rewrite data and regular expressions specified by
  542. * the LightVC user.
  543. *
  544. * Specify routes using {@link addRoute()}.
  545. *
  546. * @package lightvc
  547. * @author Anthony Bush
  548. * @since 2007-05-08
  549. **/
  550. class Lvc_RegexRewriteRouter implements Lvc_RouterInterface {
  551. protected $routes = array();
  552. /**
  553. * Specify a regular expression and how it should be routed.
  554. *
  555. * For example:
  556. *
  557. * $regexRouter->addRoute('|^wee/([^/]+)/?$|', array(
  558. * 'controller' => 'hello_world',
  559. * 'action' => 'index',
  560. * 'action_params' => array(1, 'constant_value')
  561. * ));
  562. *
  563. * would map "wee/anything" and "wee/anything/" to:
  564. *
  565. * HelloWorldController::actionIndex('anything', 'constant_value');
  566. *
  567. * but would not map "wee/anything/anything_else".
  568. *
  569. * The format of the $parsingInfo parameter is as follows:
  570. *
  571. * 'controller' => a hard coded controller name or an integer specifying which match in the regex to use.
  572. * 'action' => a hard coded action name or an integer specifying which match in the regex to use.
  573. * 'action_params' => array(
  574. * a hard coded action value or an integer specifying which match in the regex to use,
  575. * repeat above line as needed,
  576. * ),
  577. * 'additional_params' => a hard coded integer specifying which match in the regex to use for additional parameters. These will be exploded by "/" and added to the action params.
  578. *
  579. * or
  580. *
  581. * 'redirect' => a replacement string that will be used to redirect to. You can have parts of the original url mapped into the new one (like IDs). See http://www.php.net/manual/en/function.preg-replace.php's documentation for the replacement parameter.
  582. *
  583. * You can specify as much or as little as you want in the $parsingInfo.
  584. * That is, if you don't specify the controller name or action name, then
  585. * the defaults will be used by the Lvc_FrontController.
  586. *
  587. * @param $regex regular expression to match the rewritten part with.
  588. * @param $parsingInfo an array containing any custom routing info.
  589. * @return void
  590. * @author Anthony Bush
  591. * @since 2007-05-08
  592. **/
  593. public function addRoute($regex, $parsingInfo = array()) {
  594. $this->routes[$regex] = $parsingInfo;
  595. }
  596. /**
  597. * Set all routes at once. Useful if you want to specify routes in a
  598. * config file and then pass them to this router all at once. See
  599. * {@link addRoute()} for routing specifications.
  600. *
  601. * @return void
  602. * @author Anthony Bush
  603. * @since 2007-05-08
  604. **/
  605. public function setRoutes(&$routes) {
  606. $this->routes = $routes;
  607. }
  608. /**
  609. * Construct the router and set all routes at once. See {@link setRoutes()}
  610. * for more info.
  611. *
  612. * @return void
  613. * @author Anthony Bush
  614. * @see setRoutes()
  615. * @since 2007-05-09
  616. **/
  617. public function __construct(&$routes = null) {
  618. if ( ! is_null($routes)) {
  619. $this->setRoutes($routes);
  620. }
  621. }
  622. /**
  623. * Routes like {@link Lvc_RewriteRouter} does, with the additional check to
  624. * routes for specifying custom routes based on regular expressions.
  625. *
  626. * @param Lvc_HttpRequest $request A request object to route.
  627. * @return boolean
  628. * @author Anthony Bush
  629. * @since 2007-05-08
  630. **/
  631. public function route($request) {
  632. $params = $request->getParams();
  633. if (isset($params['get']['url'])) {
  634. // Use mod_rewrite's url
  635. $url = $params['get']['url'];
  636. $matches = array();
  637. foreach ($this->routes as $regex => $parsingInfo) {
  638. if (preg_match($regex, $url, $matches)) {
  639. // Check for redirect action first
  640. if (isset($parsingInfo['redirect'])) {
  641. $redirectUrl = preg_replace($regex, $parsingInfo['redirect'], $url);
  642. header('Location: ' . $redirectUrl);
  643. exit();
  644. }
  645. // Get controller name if available
  646. if (isset($parsingInfo['controller'])) {
  647. if (is_int($parsingInfo['controller'])) {
  648. // Get the controller name from the regex matches
  649. $request->setControllerName(@$matches[$parsingInfo['controller']]);
  650. } else {
  651. // Use the constant value
  652. $request->setControllerName($parsingInfo['controller']);
  653. }
  654. }
  655. // Get action name if available
  656. if (isset($parsingInfo['action'])) {
  657. if (is_int($parsingInfo['action'])) {
  658. // Get the action from the regex matches
  659. $request->setActionName(@$matches[$parsingInfo['action']]);
  660. } else {
  661. // Use the constant value
  662. $request->setActionName($parsingInfo['action']);
  663. }
  664. }
  665. // Get action parameters
  666. $actionParams = array();
  667. if (isset($parsingInfo['action_params'])) {
  668. foreach ($parsingInfo['action_params'] as $key => $value) {
  669. if (is_int($value)) {
  670. // Get the value from the regex matches
  671. if (isset($matches[$value])) {
  672. $actionParams[$key] = $matches[$value];
  673. } else {
  674. $actionParams[$key] = null;
  675. }
  676. } else {
  677. // Use the constant value
  678. $actionParams[$key] = $value;
  679. }
  680. }
  681. }
  682. if (isset($parsingInfo['additional_params'])) {
  683. if (is_int($parsingInfo['additional_params'])) {
  684. // Get the value from the regex matches
  685. if (isset($matches[$parsingInfo['additional_params']])) {
  686. $actionParams = $actionParams + explode('/', $matches[$parsingInfo['additional_params']]);
  687. }
  688. }
  689. }
  690. $request->setActionParams($actionParams);
  691. return true;
  692. } // route matched
  693. } // loop through routes
  694. } // url _GET value set
  695. return false;
  696. }
  697. }
  698. /**
  699. * FrontController takes a Request object and invokes the appropriate controller
  700. * and action.
  701. *
  702. * Example Usage:
  703. *
  704. * $fc = new Lvc_FrontController();
  705. * $fc->addRouter(new Lvc_GetRouter());
  706. * $fc->processRequest(new Lvc_HttpRequest());
  707. *
  708. * @package lightvc
  709. * @author Anthony Bush
  710. * @since 2007-04-20
  711. **/
  712. class Lvc_FrontController {
  713. protected $routers = array();
  714. /**
  715. * Add a router to give it a chance to route the request.
  716. *
  717. * The first router to return true to the {@link route()} call
  718. * will be the last router called, so add them in the order you want them
  719. * to run.
  720. *
  721. * @return void
  722. * @author Anthony Bush
  723. **/
  724. public function addRouter(Lvc_RouterInterface $router) {
  725. $this->routers[] = $router;
  726. }
  727. /**
  728. * Processes the request data by instantiating the appropriate controller and
  729. * running the appropriate action.
  730. *
  731. * @return void
  732. * @throws Lvc_Exception
  733. * @author Anthony Bush
  734. **/
  735. public function processRequest(Lvc_Request $request) {
  736. try
  737. {
  738. // Give routers a chance to (re)-route the request.
  739. foreach ($this->routers as $router) {
  740. if ($router->route($request)) {
  741. break;
  742. }
  743. }
  744. // If controller name or action name are not set, set them to default.
  745. $controllerName = $request->getControllerName();
  746. if (empty($controllerName)) {
  747. $controllerName = Lvc_Config::getDefaultControllerName();
  748. $actionName = Lvc_Config::getDefaultControllerActionName();
  749. $actionParams = $request->getActionParams() + Lvc_Config::getDefaultControllerActionParams();
  750. $request->setActionParams($actionParams);
  751. } else {
  752. $actionName = $request->getActionName();
  753. if (empty($actionName)) {
  754. $actionName = Lvc_Config::getDefaultActionName();
  755. }
  756. }
  757. $controller = Lvc_Config::getController($controllerName);
  758. if (is_null($controller)) {
  759. throw new Lvc_Exception('Unable to load controller "' . $controllerName . '"');
  760. }
  761. $controller->setControllerParams($request->getControllerParams());
  762. $controller->runAction($actionName, $request->getActionParams());
  763. }
  764. catch (Lvc_Exception $e)
  765. {
  766. // Catch exceptions and append additional error info if the request object has anything to say.
  767. $moreInfo = $request->getAdditionalErrorInfo();
  768. if (!empty($moreInfo)) {
  769. throw new Lvc_Exception($e->getMessage() . '. ' . $moreInfo);
  770. } else {
  771. throw $e;
  772. }
  773. }
  774. }
  775. }
  776. /**
  777. * The base class that all other PageControllers should extend. Depending on the setup,
  778. * you might want an AppController to extend this one, and then have all your controllers
  779. * extend your AppController.
  780. *
  781. * @package lightvc
  782. * @author Anthony Bush
  783. * @todo Finish up documentation in here...
  784. * @since 2007-04-20
  785. **/
  786. class Lvc_PageController {
  787. /**
  788. * Params is typically a combination of:
  789. * _GET (stored in params['get'])
  790. * _POST (stored in params['post'])
  791. * _FILE (also stored in params['post'])
  792. *
  793. * @var array
  794. **/
  795. protected $params = array();
  796. /**
  797. * A reference to $params['post']['data'], typically a combination of:
  798. * _POST['data'] (usually holds [Model][field])
  799. * _FILE['data'] (usually holds [key][Model][field], but the request object should remap it to [Model][field][key])
  800. *
  801. * @var array
  802. **/
  803. protected $postData = array();
  804. /**
  805. * Reference to post data (i.e. $this->params['post'])
  806. *
  807. * @var array
  808. **/
  809. protected $post = array();
  810. /**
  811. * Reference to get data (i.e. $this->params['get'])
  812. *
  813. * @var array
  814. **/
  815. protected $get = array();
  816. /**
  817. * Controller Name (e.g. controller_name, not ControllerNameController)
  818. *
  819. * @var string
  820. **/
  821. protected $controllerName = null;
  822. /**
  823. * Action Name (e.g. action_name, not actionActionName)
  824. *
  825. * @var string
  826. **/
  827. protected $actionName = null;
  828. /**
  829. * Variables we will pass to the view.
  830. *
  831. * @var array()
  832. **/
  833. protected $viewVars = array();
  834. /**
  835. * Have we loaded the view yet?
  836. *
  837. * @var boolean
  838. **/
  839. protected $hasLoadedView = false;
  840. /**
  841. * Specifies whether or not to load the default view for the action. If the
  842. * action should not render any view, set it to false in the sub controller.
  843. *
  844. * @var boolean
  845. **/
  846. protected $loadDefaultView = true;
  847. /**
  848. * Don't set this yourself. It's used internally by parent controller /
  849. * actions to determine whether or not to use the layout value in
  850. * $layoutOverride rather than in $layout when requesting a sub action.
  851. *
  852. * @var string
  853. * @see setLayoutOverride(), $layoutOverride
  854. **/
  855. protected $useLayoutOverride = false;
  856. /**
  857. * Don't set this yourself. It's used internally by parent controller /
  858. * actions to determine which layout to use when requesting a sub action.
  859. *
  860. * @var string
  861. * @see setLayoutOverride(), $useLayoutOverride
  862. **/
  863. protected $layoutOverride = null;
  864. /**
  865. * Set this in your controller to use a layout.
  866. *
  867. * @var string
  868. **/
  869. protected $layout = null;
  870. /**
  871. * An array of view variables specifically for the layout file.
  872. *
  873. * @var array
  874. **/
  875. protected $layoutVars = array();
  876. /**
  877. * Set the parameters of the controller.
  878. * Actions will get their parameters through params['get'].
  879. * Actions can access the post data as needed.
  880. *
  881. * @param array $params an array of [paramName] => [paramValue] pairs
  882. * @return void
  883. * @author Anthony Bush
  884. **/
  885. public function setControllerParams(&$params) {
  886. $this->params = $params;
  887. // Make a reference to the form data so we can get to it easier.
  888. if (isset($this->params['post']['data'])) {
  889. $this->postData =& $this->params['post']['data'];
  890. }
  891. if (isset($this->params['post'])) {
  892. $this->post =& $this->params['post'];
  893. }
  894. if (isset($this->params['get'])) {
  895. $this->get =& $this->params['get'];
  896. }
  897. }
  898. /**
  899. * Don't call this yourself. It's used internally when creating new
  900. * controllers so the controllers are aware of their name without
  901. * needing any help from a user setting a member variable or from some
  902. * reflector class.
  903. *
  904. * @return void
  905. * @author Anthony Bush
  906. **/
  907. public function setControllerName($controllerName) {
  908. $this->controllerName = $controllerName;
  909. }
  910. /**
  911. * Set a variable for the view to use.
  912. *
  913. * @param string $varName variable name to make available in the view
  914. * @param $value value of the variable.
  915. * @return void
  916. * @author Anthony Bush
  917. **/
  918. public function setVar($varName, $value) {
  919. $this->viewVars[$varName] = $value;
  920. }
  921. /**
  922. * Set variables for the view in masse.
  923. *
  924. * @param $varArray an array of [varName] => [value] pairs.
  925. * @return void
  926. * @author Anthony Bush
  927. **/
  928. public function setVars(&$varArray) {
  929. $this->viewVars = $varArray + $this->viewVars;
  930. }
  931. /**
  932. * Get the current value for a view variable.
  933. *
  934. * @param string $varName
  935. * @return mixed
  936. * @author Anthony Bush
  937. * @since 2007-11-13
  938. **/
  939. public function getVar($varName) {
  940. if (isset($this->viewVars[$varName])) {
  941. return $this->viewVars[$varName];
  942. } else {
  943. return null;
  944. }
  945. }
  946. /**
  947. * Set a variable for the layout view.
  948. *
  949. * @param $varName variable name to make available in the view
  950. * @param $value value of the variable.
  951. * @return void
  952. * @author Anthony Bush
  953. * @since 2007-05-17
  954. **/
  955. public function setLayoutVar($varName, $value) {
  956. $this->layoutVars[$varName] = $value;
  957. }
  958. /**
  959. * Get the current value for a layout variable.
  960. *
  961. * @param string $varName
  962. * @return mixed
  963. * @author Anthony Bush
  964. * @since 2007-11-13
  965. **/
  966. public function getLayoutVar($varName) {
  967. if (isset($this->layoutVars[$varName])) {
  968. return $this->layoutVars[$varName];
  969. } else {
  970. return null;
  971. }
  972. }
  973. /**
  974. * Set the layout to use for the view.
  975. *
  976. * @return void
  977. * @author Anthony Bush
  978. **/
  979. public function setLayout($layout) {
  980. $this->layout = $layout;
  981. }
  982. /**
  983. * Don't call this yourself. It's used internally when requesting sub
  984. * actions in order to avoid loading the layout multiple times.
  985. *
  986. * @return void
  987. * @see $useLayoutOverride, $layoutOverride
  988. * @author Anthony Bush
  989. **/
  990. public function setLayoutOverride($layout) {
  991. $this->useLayoutOverride = true;
  992. $this->layoutOverride = $layout;
  993. }
  994. /**
  995. * Returns the action name of this controller
  996. *
  997. * @return string
  998. * @author lzhang
  999. **/
  1000. public function getActionName()
  1001. {
  1002. return $this->actionName;
  1003. }
  1004. /**
  1005. * Determine whether or not the the controller has the specified action.
  1006. *
  1007. * @param string $actionName the action name to check for.
  1008. * @return boolean
  1009. * @author Anthony Bush
  1010. **/
  1011. public function hasAction($actionName) {
  1012. if (method_exists($this, Lvc_Config::getActionFunctionName($actionName))) {
  1013. return true;
  1014. } else {
  1015. return false;
  1016. }
  1017. }
  1018. /**
  1019. * Runs the requested action and returns the output from it.
  1020. *
  1021. * Typically called by the FrontController.
  1022. *
  1023. * @param string $actionName the action name to run.
  1024. * @param array $actionParams the parameters to pass to the action.
  1025. * @return string output from running the action.
  1026. * @author Anthony Bush
  1027. **/
  1028. public function getActionOutput($actionName, &$actionParams = array()) {
  1029. ob_start();
  1030. $this->runAction($actionName, $actionParams);
  1031. return ob_get_clean();
  1032. }
  1033. /**
  1034. * Runs the requested action and outputs its results.
  1035. *
  1036. * Typically called by the FrontController.
  1037. *
  1038. * @param string $actionName the action name to run.
  1039. * @param array $actionParams the parameters to pass to the action.
  1040. * @return void
  1041. * @throws Lvc_Exception
  1042. * @author Anthony Bush
  1043. **/
  1044. public function runAction($actionName, &$actionParams = array()) {
  1045. $this->actionName = $actionName;
  1046. $func = Lvc_Config::getActionFunctionName($actionName);
  1047. if (method_exists($this, $func)) {
  1048. $this->beforeAction();
  1049. // Call the action
  1050. if (Lvc_Config::getSendActionParamsAsArray()) {
  1051. $this->$func($actionParams);
  1052. } else {
  1053. call_user_func_array(array($this, $func), $actionParams);
  1054. }
  1055. // Load the view
  1056. if ( ! $this->hasLoadedView && $this->loadDefaultView) {
  1057. $this->loadView($this->controllerName . '/' . $actionName);
  1058. }
  1059. $this->afterAction();
  1060. return true;
  1061. } else {
  1062. throw new Lvc_Exception('No action `' . $actionName . '`. Write the `' . $func . '` method');
  1063. }
  1064. }
  1065. /**
  1066. * Load the requested controller view.
  1067. *
  1068. * For example, you can load another view in your controller with:
  1069. *
  1070. * $this->loadView($this->getControllerName() . '/some_other_action');
  1071. *
  1072. * Or some other controller with:
  1073. *
  1074. * $this->loadView('some_other_controller/some_other_action');
  1075. *
  1076. * Remember, the view for your action will be rendered automatically.
  1077. *
  1078. * @param string $controllerViewName 'controller_name/action_name' format.
  1079. * @return void
  1080. * @throws Lvc_Exception
  1081. * @author Anthony Bush
  1082. **/
  1083. protected function loadView($controllerViewName) {
  1084. $view = Lvc_Config::getControllerView($controllerViewName, $this->viewVars);
  1085. if (is_null($view)) {
  1086. throw new Lvc_Exception('Unable to load controller view "' . $controllerViewName . '" for controller "' . $this->controllerName . '"');
  1087. } else {
  1088. $view->setController($this);
  1089. $viewContents = $view->getOutput();
  1090. }
  1091. if ($this->useLayoutOverride) {
  1092. $this->layout = $this->layoutOverride;
  1093. }
  1094. if ( ! empty($this->layout)) {
  1095. // Use an explicit name for this data so we don't override some other variable...
  1096. $this->layoutVars[Lvc_Config::getLayoutContentVarName()] = $viewContents;
  1097. $layoutView = Lvc_Config::getLayoutView($this->layout, $this->layoutVars);
  1098. if (is_null($layoutView)) {
  1099. throw new Lvc_Exception('Unable to load layout view "' . $this->layout . '" for controller "' . $this->controllerName . '"');
  1100. } else {
  1101. $layoutView->setController($this);
  1102. $layoutView->output();
  1103. }
  1104. } else {
  1105. echo($viewContents);
  1106. }
  1107. $this->hasLoadedView = true;
  1108. }
  1109. /**
  1110. * Redirect to the specified url. NOTE that this function does not stop
  1111. * execution.
  1112. *
  1113. * @param string $url URL to redirect to.
  1114. * @return void
  1115. * @author Anthony Bush
  1116. **/
  1117. protected function redirect($url) {
  1118. header('Location: ' . $url);
  1119. }
  1120. /**
  1121. * Execute code before every action.
  1122. * Override this in sub classes
  1123. *
  1124. * @return void
  1125. * @author Anthony Bush
  1126. **/
  1127. protected function beforeAction() {
  1128. }
  1129. /**
  1130. * Execute code after every action.
  1131. * Override this in sub classes
  1132. *
  1133. * @return void
  1134. * @author Anthony Bush
  1135. **/
  1136. protected function afterAction() {
  1137. }
  1138. /**
  1139. * Use this inside a controller action to get the output from another
  1140. * controller's action. By default, the layout functionality will be
  1141. * disabled for this "sub" action.
  1142. *
  1143. * Example Usage:
  1144. *
  1145. * $enrollmentVerifyBox = $this->requestAction('enrollment_verify', array(), 'eligibility');
  1146. *
  1147. * @param string $actionName name of action to invoke.
  1148. * @param array $actionParams parameters to invoke the action with.
  1149. * @param string $controllerName optional controller name. Current controller will be used if not specified.
  1150. * @param array $controllerParams optional controller params. Current controller params will be passed on if not specified.
  1151. * @param string $layout optional layout to force for the sub action.
  1152. * @return string output from requested controller's action.
  1153. * @throws Lvc_Exception
  1154. * @author Anthony Bush
  1155. **/
  1156. protected function requestAction($actionName, $actionParams = array(), $controllerName = null, $controllerParams = null, $layout = null) {
  1157. if (empty($controllerName)) {
  1158. $controllerName = $this->controllerName;
  1159. }
  1160. if (is_null($controllerParams)) {
  1161. $controllerParams = $this->params;
  1162. }
  1163. $controller = Lvc_Config::getController($controllerName);
  1164. if (is_null($controller)) {
  1165. throw new Lvc_Exception('Unable to load controller "' . $controllerName . '"');
  1166. }
  1167. $controller->setControllerParams($controllerParams);
  1168. $controller->setLayoutOverride($layout);
  1169. return $controller->getActionOutput($actionName, $actionParams);
  1170. }
  1171. /**
  1172. * Get the controller name. Mostly used internally...
  1173. *
  1174. * @return string controller name
  1175. * @author Anthony Bush
  1176. **/
  1177. public function getControllerName() {
  1178. return $this->controllerName;
  1179. }
  1180. /**
  1181. * Get the controller params. Mostly used internally...
  1182. *
  1183. * @return array controller params
  1184. * @author Anthony Bush
  1185. **/
  1186. public function getControllerParams() {
  1187. return $this->params;
  1188. }
  1189. }
  1190. /**
  1191. * A View can be outputted or have its output returned (i.e. it's renderable).
  1192. * It can not be executed.
  1193. *
  1194. * $inc = new Lvc_View('foo.php', array());
  1195. * $inc->output();
  1196. * $output = $inc->getOutput();
  1197. *
  1198. * @package lightvc
  1199. * @author Anthony Bush
  1200. * @since 2007-04-20
  1201. **/
  1202. class Lvc_View {
  1203. /**
  1204. * Full path to file name to be included.
  1205. *
  1206. * @var string
  1207. **/
  1208. protected $fileName;
  1209. /**
  1210. * Data to be exposed to the view template file.
  1211. *
  1212. * @var array
  1213. **/
  1214. protected $data;
  1215. /**
  1216. * A reference to the parent controller
  1217. *
  1218. * @var Lvc_Controller
  1219. **/
  1220. protected $controller;
  1221. /**
  1222. * Construct a view to be rendered.
  1223. *
  1224. * @param string $fileName Full path to file name of the view template file.
  1225. * @param array $data an array of [varName] => [value] pairs. Each varName will be made available to the view.
  1226. * @return void
  1227. * @author Anthony Bush
  1228. **/
  1229. public function __construct($fileName, &$data) {
  1230. $this->fileName = $fileName;
  1231. $this->data = $data;
  1232. }
  1233. /**
  1234. * Output the view (aka render).
  1235. *
  1236. * @return void
  1237. * @author Anthony Bush
  1238. **/
  1239. public function output() {
  1240. extract($this->data, EXTR_SKIP);
  1241. include($this->fileName);
  1242. }
  1243. /**
  1244. * Return the output of the view.
  1245. *
  1246. * @return string output of view
  1247. * @author Anthony Bush
  1248. **/
  1249. public function getOutput() {
  1250. ob_start();
  1251. $this->output();
  1252. return ob_get_clean();
  1253. }
  1254. /**
  1255. * Render a sub element from within a view.
  1256. *
  1257. * Views are not allowed to have business logic, but they can call upon
  1258. * other generic, shared, views, called elements here.
  1259. *
  1260. * @param string $elementName name of element to render
  1261. * @param array $data optional data to pass to the element.
  1262. * @return void
  1263. * @throws Lvc_Exception
  1264. * @author Anthony Bush
  1265. **/
  1266. protected function renderElement($elementName, $data = array()) {
  1267. $view = Lvc_Config::getElementView($elementName, $data);
  1268. if (!is_null($view)) {
  1269. $view->setController($this->controller);
  1270. $view->output();
  1271. } else {
  1272. error_log('Unable to render element "' . $elementName . '"');
  1273. // throw new Lvc_Exception('Unable to render element "' . $elementName . '"');
  1274. }
  1275. }
  1276. /**
  1277. * Set the controller when constructing a view if you want {@link setLayoutVar()}
  1278. * to be callable from a view.
  1279. *
  1280. * @return void
  1281. * @author Anthony Bush
  1282. * @since 2007-05-17
  1283. **/
  1284. public function setController($controller) {
  1285. $this->controller = $controller;
  1286. }
  1287. /**
  1288. * Set a variable for the layout file. You can set the page title from a static
  1289. * page's view file this way.
  1290. *
  1291. * @param $varName variable name to make available in the view
  1292. * @param $value value of the variable.
  1293. * @return void
  1294. * @author Anthony Bush
  1295. * @since 2007-05-17
  1296. **/
  1297. public function setLayoutVar($varName, $value) {
  1298. $this->controller->setLayoutVar($varName, $value);
  1299. }
  1300. }
  1301. ?>