Route.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. namespace Goodquestiondev;
  3. use Illuminate\Support\Str;
  4. use Goodquestiondev\Resource;
  5. use Goodquestiondev\Controllers\Controller;
  6. use Symfony\Component\HttpFoundation\Request;
  7. class Route
  8. {
  9. /**
  10. * The Application routers
  11. *
  12. * @var array
  13. */
  14. public $resources = [];
  15. /**
  16. * The Application instance.
  17. *
  18. * @var self
  19. */
  20. private static $instance = null;
  21. /**
  22. * The default actions for a resourceful controller.
  23. *
  24. * @var array
  25. */
  26. public $resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy'];
  27. /**
  28. * The verbs used in the resource URIs.
  29. *
  30. * @var array
  31. */
  32. public static $verbs = [
  33. 'create',
  34. 'edit',
  35. ];
  36. /**
  37. * The possible resource keys
  38. *
  39. * @var array
  40. */
  41. public $resourceKeys = [];
  42. /**
  43. * The resource strings
  44. *
  45. * @var array
  46. */
  47. public $resourceStrings = [];
  48. /**
  49. * Create a new simple resource instance following singleton pattern
  50. *
  51. * @return self
  52. */
  53. public static function getInstance()
  54. {
  55. if (self::$instance == null) {
  56. self::$instance = new self();
  57. }
  58. return self::$instance;
  59. }
  60. /**
  61. * Register resource
  62. *
  63. * @param string $uri The uri string
  64. *
  65. * @return void
  66. */
  67. public static function resource(string $uri)
  68. {
  69. $route = self::getInstance();
  70. $resourceKeys = array_merge(explode(".", $uri), $route->resourceKeys);
  71. $route->resourceKeys = array_unique($resourceKeys);
  72. $route->resourceStrings[] = $uri;
  73. $route->resources[$uri] = new Resource($uri);
  74. }
  75. /**
  76. * Redirects the user to the correct controller and method based on the path
  77. *
  78. * @param Request $request The request data content
  79. *
  80. * @return Resource
  81. */
  82. public static function getResource($request)
  83. {
  84. $route = self::getInstance();
  85. $uriInfo = $route->getUriInfo($request->getPathInfo());
  86. $resourceExists = false;
  87. foreach ($route->resources as $resource) {
  88. if (in_array($uriInfo['uri'], $resource->uriList)) {
  89. $route->callController($resource, $request, $uriInfo);
  90. $resourceExists = true;
  91. }
  92. }
  93. if (! $resourceExists) {
  94. throw new \Exception('Error getting the Resource: ' . __FUNCTION__);
  95. }
  96. }
  97. /**
  98. * Get URI and their params
  99. * E.q for path /users/bob/posts/999
  100. * E.q: ['uri' => 'users/{key}posts/{key}', 'params' ['users' => 'bob', 'posts' => 999]]
  101. *
  102. * @param string $path The request path
  103. *
  104. * @return array
  105. */
  106. public function getUriInfo($path)
  107. {
  108. $path = Str::of($path)->ltrim('/')->rtrim('/');
  109. $parts = explode("/", $path);
  110. $params = [];
  111. $uri = '';
  112. foreach ($parts as $index => $part) {
  113. $isResourceString = in_array($part, $this->resourceKeys);
  114. if ($index === 0 && ! $isResourceString) {
  115. throw new \Exception('Bad Url');
  116. }
  117. $isResourceVerb = in_array($part, self::$verbs);
  118. if ($isResourceVerb) {
  119. $uri .= $part;
  120. break;
  121. }
  122. if ($isResourceString) {
  123. $params[$part] = '';
  124. $uri .= "$part/";
  125. } else {
  126. $params[array_key_last($params)] = $part;
  127. $singular = Str::singular(array_key_last($params));
  128. $uri .= "{{$singular}}/";
  129. }
  130. }
  131. foreach ($params as $key => $value) {
  132. unset($params[$key]);
  133. $params[Str::singular($key)] = $value;
  134. }
  135. return [
  136. 'uri' => (string) Str::of($uri)->rtrim('/'),
  137. 'params' => $params
  138. ];
  139. }
  140. /**
  141. * Find controller and instantiate it
  142. *
  143. * @param Resource $resource The Resource verb
  144. * @param Request $request The request
  145. * @param array $uriInfo The url info
  146. *
  147. * @return void
  148. */
  149. public function callController(Resource $resource, Request $request, array $uriInfo)
  150. {
  151. $app = Application::getInstance();
  152. try {
  153. $controllerClassName = $app->controllerUris[$resource->uri];
  154. $controllerName = "Goodquestiondev\\Controllers\\{$controllerClassName}";
  155. $controller = new $controllerName;
  156. } catch (\Exception $e) {
  157. throw new \Exception('Error getting Controller');
  158. }
  159. $this->callAction($controller, $resource, $request, $uriInfo);
  160. }
  161. /**
  162. * Call the Controller method
  163. *
  164. * @param Controller $controller The controller
  165. * @param Resource $resource The Resource verb
  166. * @param Request $request The request
  167. *
  168. * @return void
  169. */
  170. public function callAction(Controller $controller, Resource $resource, Request $request, array $uriInfo)
  171. {
  172. $path = $request->getPathInfo();
  173. switch ($request->getMethod()) {
  174. case 'GET':
  175. if (Str::contains($path, 'create')) {
  176. $controller->create();
  177. break;
  178. }
  179. if (Str::contains($path, 'edit')) {
  180. $controller->edit($uriInfo['params']);
  181. break;
  182. }
  183. if (Str::contains($uriInfo['uri'], '{')) {
  184. $controller->show($uriInfo['params']);
  185. break;
  186. }
  187. $controller->index();
  188. break;
  189. case 'POST':
  190. $controller->store($request);
  191. break;
  192. case 'PUT':
  193. case 'PATCH':
  194. $controller->update($request, $uriInfo['params']);
  195. break;
  196. case 'DELETE':
  197. $controller->destroy($uriInfo['params']);
  198. break;
  199. default:
  200. $controller->error($request);
  201. }
  202. }
  203. }