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

/src/server/receptors/IdentityDispatcher.class.php

http://floe.googlecode.com/
PHP | 130 lines | 76 code | 10 blank | 44 comment | 25 complexity | 9fafc889ad26d1171ec69a7c8eeb76e1 MD5 | raw file
Possible License(s): LGPL-2.0
  1. <?php
  2. /**
  3. * This file is part of Floe, a graceful PHP framework.
  4. * Copyright (C) 2005-2009 Mark Rickerby <http://maetl.net>
  5. *
  6. * See the LICENSE file distributed with this software for full copyright, disclaimer
  7. * of liability, and the specific limitations that govern the use of this software.
  8. *
  9. * @version $Id: IdentityDispatcher.class.php 396 2010-05-19 13:13:55Z coretxt $
  10. * @package server
  11. * @subpackage receptors
  12. */
  13. /**#@+
  14. * Required dependency.
  15. */
  16. require_once dirname(__FILE__) .'/../../framework/EventLog.class.php';
  17. require_once dirname(__FILE__) .'/../../language/en/Inflect.class.php';
  18. require_once dirname(__FILE__) .'/../controllers/IdentityController.class.php';
  19. require_once dirname(__FILE__).'/../ResourceNotFound.class.php';
  20. /**#@-*/
  21. if (defined('DefaultMethodBinding')) {
  22. throw new Exception("Deprecated constant [DefaultMethodBinding]. Please use [IdentityDispatcher_DefaultBinding]");
  23. }
  24. if (defined('BindMissingDefault')) {
  25. throw new Exception("Deprecated constant [BindMissingDefault]. Please use [IdentityDispatcher_BindMissing]");
  26. }
  27. /**
  28. * Bind base URL requests to this controller method by default.
  29. */
  30. if (!defined('IdentityDispatcher_DefaultBinding')) define('IdentityDispatcher_DefaultBinding', 'index');
  31. /**
  32. * Delegates request binding to a controller based on URI identity.
  33. *
  34. * <p>The identity binding is based on a simple heirachical convention
  35. * for invoking controller methods:</p>
  36. *
  37. * - /thing/action => maps to the ThingController::action() method
  38. * - /thing/action/id => maps to the ThingController:action() method and passes the ID as a parameter
  39. * - /thing => maps to the ThingController::index() method
  40. * - / => maps to the IndexController::index() method
  41. *
  42. * <p>The default URL mapping will throw a ResourceNotFound exception if no controller exists by that name.
  43. * To override this behavior, and route all requests to a controller method binding, define a constant
  44. * <code>BindMissingDefault</code> in your app configuration. This will load the default controller on
  45. * all URL requests, and leaves 404 handling up to you.</p>
  46. *
  47. * @package server
  48. * @subpackage receptors
  49. * @todo document the precedence heirachy and refactor to better communicate what this code does
  50. */
  51. class IdentityDispatcher implements Receptor {
  52. /**
  53. * Look for a controller that maps to the URI
  54. * and invoke its identity method.
  55. */
  56. public function run(Request $request, Response $response) {
  57. $base = (count($request->uri->segments()) == 1) ? $request->uri->identity() : $request->uri->segment(0);
  58. $identity = $request->uri->segment(1);
  59. $params = $request->uri->segmentsFrom(2);
  60. if ($base == '') $base = IdentityDispatcher_DefaultBinding;
  61. if ($identity == '') $identity = $base;
  62. $path = CTR_DIR ."/$base.controller.php";
  63. if (!file_exists($path)) {
  64. $path = CTR_DIR ."/$base/$identity.controller.php";
  65. $base = $identity;
  66. $identity = $request->uri->segment(2);
  67. if ($identity == '') $identity = $base;
  68. $params = $request->uri->segmentsFrom(3);
  69. if (!file_exists($path) && defined('IdentityDispatcher_BindMissing')) {
  70. $base = IdentityDispatcher_DefaultBinding;
  71. $path = CTR_DIR ."/$base.controller.php";
  72. $params = $request->uri->segmentsFrom(0);
  73. if (!$path) {
  74. throw new ResourceNotFound("Controller not found", $path);
  75. }
  76. }
  77. }
  78. if (file_exists($path)) {
  79. include_once $path;
  80. } else {
  81. if (file_exists(TPL_DIR.'/'.$base.'.php')) {
  82. $response->render($base);
  83. return;
  84. } else {
  85. throw new ResourceNotFound("Controller file not found", $path);
  86. }
  87. }
  88. $classname = Inflect::toClassName($base).'Controller';
  89. if (class_exists($classname)) {
  90. $controller = new $classname($request, $response);
  91. } else {
  92. throw new ResourceNotFound("Controller $classname not defined", $path);
  93. }
  94. $identity = $this->stripActionIdentifier($identity);
  95. if (method_exists($controller, $identity)) {
  96. $this->invoke($controller, $identity, $params);
  97. } elseif (method_exists($controller, IdentityDispatcher_DefaultBinding)) {
  98. $this->invoke($controller, IdentityDispatcher_DefaultBinding, $request->uri->segmentsFrom(1));
  99. } else {
  100. throw new ResourceNotFound("Method $identity not defined in $classname", $path);
  101. }
  102. }
  103. private function stripActionIdentifier($identity) {
  104. // converts base action to a compatible format
  105. $identity = strtolower(Inflect::underscore(Inflect::decodeUriPart($identity)));
  106. // returns the base action name without a file extension
  107. if (strstr($identity, '.')) {
  108. $identity = explode('.', $identity);
  109. $identity = $identity[0];
  110. }
  111. return $identity;
  112. }
  113. private function invoke($controller, $identity, $params) {
  114. EventLog::info(sprintf("Invoked [%s->%s(%s)]", get_class($controller), $identity, implode(",", $params)));
  115. if (method_exists($controller, 'before')) call_user_func(array($controller, 'before'));
  116. call_user_func_array(array($controller, $identity), $params);
  117. if (method_exists($controller, 'after')) call_user_func(array($controller, 'after'));
  118. }
  119. }
  120. ?>