PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Website/ext/moor/README.markdown

https://github.com/chandu2406/KodeKombat-server
Markdown | 461 lines | 303 code | 158 blank | 0 comment | 0 complexity | f762d7d047596934b375d5d56c8962d5 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. # Moor
  2. A URL Routing/Linking/Controller library for PHP 5.1+.
  3. - Introduction
  4. - Concepts To Understand
  5. - Hello World (PHP 5.1+)
  6. - Hello World (PHP 5.3+)
  7. - Initial Set Up
  8. - URL Routing
  9. - Request Parameters
  10. - Callback Parameters
  11. - Valid Callbacks
  12. - Link Generation
  13. - Path Generation
  14. - Active Callback Helpers
  15. - 404 Callback
  16. - Triggers
  17. - Debugging
  18. - Built-In Controllers
  19. - Tips
  20. - Linking Helper
  21. - Issues & Errata
  22. - Credits
  23. ## Introduction
  24. Moor is a URL Routing/Linking/Controller library for PHP 5. It performs 2 actions very well: routing URLs to callbacks and generating URLs for callbacks.
  25. While an understanding of MVC will help your grasp Moor's role in your application, Moor is not an MVC framework. It's a library that only helps with routing, linking, and organizing your controller logic. Use your favorite ORM for your Models and your favorite templating system for your Views. If you don't need or want these pieces, write cool stuff without them.
  26. *This is currently beta software.* It is released under the MIT license.
  27. ## Concepts To Understand
  28. If you don't have a basic understanding of the following concepts/techniques, you will be at a severe disadvantage. Please read up if you have to.
  29. [Wikipedia MVC Page](http://en.wikipedia.org/wiki/Model-view-controller)
  30. ## Hello World (PHP 5.1+)
  31. <?php
  32. Moor::route('/hello/:name', 'hello_world')->run();
  33. function hello_world() {
  34. echo 'HELLO WORLD to ' . $_GET['name'];
  35. }
  36. ## Hello World (PHP 5.3+)
  37. <?php
  38. Moor::route('/hello/:name', function(){
  39. echo 'HELLO WORLD to ' . $_GET['name'];
  40. })->run();
  41. ## Initial Set Up
  42. Not much is needed to set up Moor. With your HTTP Server of choice, simply route all requests for paths/files that don't exists to a single PHP script. This pattern is typically referred to as a Front Controller. In Apache, these rules can be placed in your .htaccess:
  43. # route non-existant requests to single script
  44. RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} !-f
  45. RewriteRule ^.*$ bootstrap.php [QSA,NS]
  46. Somewhere in your script, either bootstrap, or (I prefer) another included file, load up Moor!
  47. include /path/to/libraries/moor/Moor.php;
  48. Then you are good to go! Load any other libraries, configure your app(s), and define your Moor options/routes.
  49. ## URL Routing
  50. The primary feature of Moor is routing URLs to a callback. This is achieved with the Moor::route method. Moor::route takes 3 parameters in a few configurations: a URL definition, a valid callback, and a closure. The PHP Callback can be any valid PHP callback: function or method. For security reasons, if calling a method, the class must extend (at-least) MoorAbstractController.
  51. // Will run function 'home_page' on /
  52. Moor::route('/', 'home_page');
  53. // Will run method 'Apps::list' on /apps
  54. // Remember! Class Apps should extend (at least) MoorAbstractController
  55. Moor::route('/apps', 'Apps::list');
  56. // Will run Site\Home::index on /my-site
  57. Moor::route('/my-site', 'Site\Home::index');
  58. // You can also chain routes together
  59. Moor::
  60. route('/', 'home')->
  61. route('/page1', 'page_one')->
  62. route('/page2', 'page_two');
  63. By default, routes are matched from beginning to end, but we can change this behavior by adding wildcards to the beginning and/or end of our URL definition. They are not valid elsewhere in the URL.
  64. // Will run function start_app on /app/anything-can-go-here
  65. Moor::route('/app/*', 'start_app');
  66. // Will run function my_resouse on /anything-can-go-here/end
  67. // URL definitions starting with a wildcard cannot be linked to! (see Link Generation)
  68. Moor::route('*/end, 'my_resource');
  69. If we're using a closure (5.3+), we can replace the second callback parameter.
  70. Moor::route('/', function(){
  71. // do stuff!
  72. });
  73. However, we now have no way of referencing the route in order to link back to it, so most of the time we're probably best leaving a function name as the second parameter and our closure as the third parameter
  74. Moor::route('/', 'home', function(){
  75. // do stuff! and we can generate a link to this! :-)
  76. });
  77. URL routing is triggered when Moor::run is called.
  78. Moor::run();
  79. It's nice when you chain it on the end of some routes.
  80. Moor::
  81. route('/', 'home')->
  82. route('/page1', 'page_one')->
  83. route('/page2', 'page_two')->
  84. run();
  85. Moor::setUrlPrefix can be used to route URLs which all have a common string at the beginning, such as when installed in a subfolder of a website. The prefix will be added to every $url_string passed to Moor::route.
  86. Moor::setUrlPrefix('/folder/to/route/under/')->
  87. route('page1', 'page_one')->
  88. route('page2', 'page_two');
  89. ### Request Parameters
  90. Parameters can be extracted from URLs by using a prepending a URL piece with a colon, i.e. :var_name. By default, they are matched by the pattern [0-9A-Za-z\_]+.
  91. // Will match /[0-9A-Za-z_-]+ and put the value of 'name' in $_GET
  92. Moor::route('/:name', 'my_callback');
  93. // other examples
  94. Moor::route('/users/:id', 'MyApp\User::read');
  95. If we need to match a specific pattern, we can add a pattern in parenthesis after the request parameter definition.
  96. // only match digits for the :id param
  97. Moor::route('/users/:id(\d+)', 'MyApp\User::read');
  98. To change the default request param pattern, use Moor::setRequestParamPattern:
  99. Moor::setRequestParamPattern('[A-Z_]+');
  100. ### Callback Parameters
  101. A lot of times the callbacks provided won't (and shouldn't) be static, so we have to allow for parameters from the url to be moved into the callback. These are similar to request parameters, but are prefixed with an @. All callback parameters are available in the callback definition.
  102. Moor::route('/@class/:id/@method', '@class::@method');
  103. // incoming /user/4/delete resolves to user::delete AND $_GET['id'] = 4
  104. // incoming /user/5/activate resolves to user::activate AND $_GET['id'] = 5
  105. // incoming /groups/3/update resolves to groups::update AND $_GET['id'] = 3
  106. Moor::route('/@class/:id, '@class::read');
  107. // incoming /user/4 resolves to user::read and $_GET['id] = 4
  108. Typically, we need to format the callback params to fit with our own coding standard, so we can add formatting rules in parenthesis after the callback parameter definition. There are currently 3 formatting rules that can be applied.
  109. u => underscore (default, used if no formatting rule is specified)
  110. lc => lowerCamelCase
  111. cc => UpperCamelCase
  112. Moor::route('/@class/:id/@method', '@class(uc)::@method(lc)');
  113. // incoming /user/4/delete_me resolves to User::delete AND $_GET['id'] = 4
  114. // incoming /user/5/activate resolves to User::activate AND $_GET['id'] = 5
  115. // incoming /user/4/run_script resolves to User::runScript AND $_GET['id'] = 4
  116. // incoming /groups/3/update resolves to Groups::update AND $_GET['id'] = 3
  117. The names of callback params are arbitrary. Just build a valid callback with them.
  118. Moor::route('/@c/:id/@m', '@c(uc)::@m(lc)');
  119. The only rule is that you must use have the same callback params in the URL and callback definitions.
  120. Moor::route('/@namespace/@class/:id/@method', '@class(uc)::@method(lc)');
  121. // Mismatched callback params! Will throw a MoorProgrammerException
  122. ### Valid Callbacks
  123. For security reasons, some callbacks are not valid. Here are the requirements for callbacks:
  124. __Closures__
  125. - No requirements, all closure callbacks are valid
  126. __Functions__
  127. - Cannot be *fully* dynamic: '@function' or '@namespace\@function', as opposed to the valid: 'totally\_static\_func', 'MyNamespace\@function' or 'functions\_@name'
  128. __Methods__
  129. - Class must be a subclass of MoorAbstractController
  130. - Method name cannot start with \_\_ (to protect magic methods)
  131. - Method must have public visibility
  132. ## Link Generation
  133. Moor can generate links to any callback defined in a route. Let's say we define the following routes.
  134. Moor::route('/:name(u)', 'home', function(){
  135. 'Welcome, ' . $_GET['name'];
  136. });
  137. Moor::
  138. route('/@class(u)/:id/@action(u)', '@class(uc)::@method(lc)')->
  139. route('/@class(u)/:id', '@class(uc)::read')->
  140. route('/@class(u)/:id.:format([a-z]{1,3})', @class(uc)::read')->
  141. route('/@class(u)', '@class(uc)::index')->
  142. run();
  143. Note the formatting rules in the URL definition callback params. Just as we defined these rules in the callback, we can define in the URL, above we are explicitly saying "convert the callback to underscore format" across the board. Linking to User::delete w/ id of 4 will generate /user/4/delete. See how User became user for the url? a class named UserGroup would become user\_group for the URL.
  144. Typically, we'll always want underscore format for the URL callback params, so we can drop that formatting rule altogether as it's the default.
  145. Moor::route('/:name)', 'home', function(){
  146. 'Welcome, ' . $_GET['name'];
  147. });
  148. Moor::
  149. route('/@class/:id/@action', '@class(uc)::@method(lc)')->
  150. route('/@class/:id.:format([a-z]{1,4})', @class(uc)::read')->
  151. route('/@class/:id', '@class(uc)::read')->
  152. route('/@class', '@class(uc)::index')->
  153. run();
  154. Great. But how to we generate links?? We can with the Moor::linkTo method. This method takes the callback (or closure name) plus colon (and optionally space) separated request param names we want to pass, then a variable length argument list of the values of those params. Look at these examples:
  155. Moor::linkTo('Users::delete :id', 1);
  156. // generates /users/1/delete
  157. Moor::linkTo('Users::read :id', 200);
  158. // generates /users/200
  159. Moor::linkTo('Users::read :id :format', 5, 'json');
  160. // generates /users/5.json
  161. Moor::linkTo('Users::index');
  162. // generates /users
  163. Moor::linkTo('home :name', 'bob');
  164. // generates /bob;
  165. Moor::linkTo('No\Way::jose');
  166. // no callback match can be found, throws a MoorProgrammerException
  167. Request params that don't exist in the URL definition are appended to the query string.
  168. Moor::linkTo('Users::update :id :name', 17, 'john');
  169. // generates /users/17/update?name=john
  170. If you want to link to a method callback within the current active class, linkTo can accept a wildcard in the callback:
  171. Moor::linkTo('*::edit');
  172. // links to Users::edit if our currently running callback is in the Users class.
  173. This can also be used on the namespace level:
  174. // 5.3+ style namespaces
  175. Moor::linkTo('*\my_function');
  176. Moor::linkTo('*\Users::edit');
  177. // 5.1+ style namespaces will consider anything before an _CamelCase class name as a namespace
  178. // Example: Admin_Users::edit => namespace will be Admin
  179. Moor::linkTo('*_Users::edit');
  180. We can only use linkTo once Moor's router has been started with run(). If the route cannot be found, Moor::linkTo will throw a MoorProgrammerException. Currently, Moor considers a callback valid if it matches a route and does not determine if the callback actually exists.
  181. ## Path Generation
  182. Typically, it's convenient to map your callbacks to file paths in order to pull in associated files, such as views. We can generate a path with Moor::pathTo(). This method takes the same argument style as Moor::linkTo(), minus the request params.
  183. Moor::pathTo('User::edit');
  184. // returns /user/edit
  185. Moor::pathTo('Dashboard\Groups::add');
  186. // returns /dashboard/groups/add
  187. Moor::pathTo('Admin_StoreItems::delete');
  188. // returns /admin/store_items/delete
  189. Moor::pathTo('*::index');
  190. // returns path to /ACTIVE-CLASS/index
  191. Or, as a convenience, there are two active path methods to generate paths for running callbacks which are described in the next section.
  192. ## Active Callback Helpers
  193. Moor defines some methods to help get information about the current active/running callback. If the callback you've defined in your route doesn't contain one of these pieces, that pieces' function will simply return NULL.
  194. Moor::getActiveCallback()
  195. // returns the currently running callback in it's full form
  196. Moor::getActiveClass()
  197. // returns the class name (plus namespace) of the currently running callback
  198. Moor::getActiveFunction()
  199. // returns the function name of the currently running callback
  200. Moor::getActiveMethod()
  201. // returns the method name (plus namespace & class) of the currently running callback
  202. Moor::getActiveNamespace()
  203. // returns the namespace of the currently running callback
  204. Moor::getActiveShortClass()
  205. // returns the class name (minus namespace) of the currently running callback
  206. Moor::getActiveShortMethod()
  207. // returns the method name (minus namespace & class) of the currently running callback
  208. Moor::getActivePath();
  209. // returns the generated path for the currently running callback
  210. Moor::getActiveClassPath();
  211. // returns the generated path for the currently running callback's class
  212. ## 404 Callback
  213. There is a default callback that is run when a route cannot be found: Moor::routeNotFoundCallback. This can be changed with:
  214. Moor::setNotFoundCallback('Your::own404Callback');
  215. Please note that the default not found callback can optionally display debugging information, so if you still wanted debug messages, you would need to add this functionality to your custom callback.
  216. ## Triggers
  217. While the router is running:
  218. - Trigger the 404 callback with Moor::triggerNotFound().
  219. - Skip the current active route and continue routing with Moor::triggerContinue().
  220. ## Debugging
  221. Enable debugging on the default 404 page with:
  222. Moor::enableDebug();
  223. // you can also check if debugging is
  224. // enabled with: Moor::getDebug()
  225. Debugging is off by default. If you are creating your own 404 page, you can get an array of all debug messages with:
  226. Moor::getMessages();
  227. ## Built-In Controllers
  228. Moor currently comes with two built in controller classes. MoorAbstractController and MoorActionController. If neither suit your needs, you're encouraged to extend MoorAbstractController and create your own controller classes.
  229. MoorAbstractController is as simple as it gets:
  230. class MoorAbstractController {
  231. public function __construct() {
  232. call_user_func(array(
  233. $this, Moor::getActiveShortMethod()
  234. ));
  235. }
  236. }
  237. // When a method callback is matched, and the class of that callback
  238. // is a subclass of MoorAbstractController, Moor instantiates the
  239. // extending class in which __construct calls the public instance method.
  240. MoorActionController is built on top of MoorAbstractController, but has some special features that set it apart and make it more appealing for writing an application. The built in helper methods are:
  241. protected function beforeAction() { ...
  242. // Will be called before all action methods
  243. protected function afterAction() { ...
  244. // Will be called after all action method (and exception handlers)
  245. protected function catch{EXCEPTION_NAME}($e) { ...
  246. // Will catch the specified exception throw within the action method
  247. // Accepts one argument: the exception instance.
  248. Here is an example of these methods in action:
  249. class Users extends MoorActionController() {
  250. protected function beforeAction() {
  251. // Called before all action methods
  252. }
  253. public function myAction() {
  254. // My action logic is here after __before
  255. $this-x = $this->myHelper();
  256. }
  257. public function myUnstableAction() {
  258. throw new FrameworkException($e);
  259. }
  260. protected function catchFrameworkException($e) {
  261. // Will catch FrameworkException (or a subclass of) then continue to afterAction
  262. }
  263. protected function catchException($e) {
  264. // Will catch Exception (or a subclass of), then continue to afterAction
  265. }
  266. protected function afterAction() {
  267. // Called after the action method (and possibly an exception handler.)
  268. }
  269. // We can use the valid callback rules to our advantage.
  270. // Below is a helper method that is not accessible through
  271. // any URL because its visibility is not public. Secure
  272. // anything that's meant for internal use only.
  273. protected function myHelper() {
  274. return 'help';
  275. }
  276. }
  277. ## Tips & Extras
  278. ### Linking Helper
  279. You'll probably not want to write Moor::linkTo() everywhere, so it's usually nice to write a global function . I typically use link_to() or l().
  280. function link_to() {
  281. $args = func_get_args();
  282. return call_user_func_array(
  283. 'Moor::linkTo', $args
  284. );
  285. }
  286. ### Simple Views
  287. Views (or any kind of templates) aren't built in to Moor, but that doesn't mean they aren't an important part of your app. Powerful templating engines are fine, but I prefer keeping things simple. PHP has free templating, so the easiest way to implement a template/view system is to simply include a file. This pattern has worked well for me .
  288. define('PATH_TO_VIEWS', '/path/to/your/views');
  289. function render($callback, $controller_instance=NULL, $format='html') {
  290. $_moor_view_file = PATH_TO_VIEWS . Moor::pathTo($callback) . ".{$format}.php",
  291. if (!file_exists($_moor_view_file)) { return; }
  292. unset($path_to_callback, $controller_instance, $format);
  293. if (is_object($controller_instance)) {
  294. extract(get_object_vars($controller_instance), EXTR_REFS);
  295. }
  296. include $moor_view_file;
  297. }
  298. Usually, this is enough, and it can be called from the afterMethod
  299. ## Issues & Errata
  300. Please submit and issues or errata through the [issue tracker on GitHub](http://github.com/jeffturcotte/moor/issues). Your help is appreciated.
  301. ## Credits
  302. Designed and programmed by Jeff Turcotte.
  303. (c) 2010