Skip to content

rsesek/hoplite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

77 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hoplite                                              A lightweight MVC framework
================================================================================

Hoplite is the successor framework to phalanx. While many of the ideas in
phalanx were good starting point explorations, it was ultimately over-
engineered. Hoplite aims to be a no-frills web framework--a starting point for
applications that can incorporate other technologies.

--------------------------------------------------------------------------------

Basic flow:

1. HTTP request is made.
2. Web server (Apache, Lighty, etc.) receive the request and route it, via
   mod_rewrite or something similar to the entrypoint, which is typically
   index.php.
3. RootController is initialized and Run with the $GLOBALS (_GET, _POST, etc.).
4. A HttpRequest object is created with the initializing data.
5. A UrlMap matches a URL prefix (with pathc component extraction) to an Action.
6. The Action produces a HttpResponse to the Request.
7. An OutputFilter examines the Request and Response to create the body of the
   HTTP response.

--------------------------------------------------------------------------------

Actions:

The base Action class is abstract and has three states: before, acting, and
after:

Action {
  __construct(RootController)

  controller() -> RootController

  FilterRequest(HttpRequest, HttpResponse)

  Invoke(HttpRequest, HttpResponse)

  FilterResponse(HttpResponse, HttpResponse)
}

The filter methods are available for two reasons:
  1. To validate data in the request
  2. To format data in the response

These hook points can also be used to implement interceptors, with the aid of
the RootController interface.

RootController {
  __construct($GLOBALS)

  Run()
  Stop()

  RouteRequest(string)
  InvokeAction(Action)

  LookupAction(string)
}

In the entrypoint, the RootController is Run(). This creates and owns the
Request and Response objects. At any point when an Action is executing, it can
invoke control-flow changing methods on the controller. Stop() will force the
OutputFilter to run and will terminate the program. InvokeAction() will replace
the current Action with the parameter. This will move the Action between its
states.

RouteRequest() is called by Run() to perform the evaluation and lookup of the
UrlMap. This may also be called to perform an internal redirect. Note that this
will reuse the existing Request and Response objects.

Finally LookupAction() performs a reverse-lookup of class name to URL patterns.

--------------------------------------------------------------------------------

Advanced actions:

The basic Action is abstract. For creating individual pages, this merely
overriding Invoke() can be used to fill the HttpResponse's body for simple HTML
output.

RestActions are a special kind of action, where Invoke() will further dispatch
the request based on the HTTP method. This makes creating RESTful web services
and AJAX applications easy:

RestAction : Action {
  DoGet(HttpRequest, HttpResponse)
  DoPost(...)
  DoDelete(...)
  DoPut(...)
}

Another type of action is an ActionController, which maps a URL path component
to a method in the typical MVC style. The ActionController will look at the
'action' key in the HttpRequest's data dictionary to determine which method to
invoke. For example, if you had this entry in the UrlMap:

  'user/{action}/{id}' => 'UserActionController'

Then the UrlMap would extract the 'action' and 'id' paramters and add them to
the HttpRequest object. If 'action' were 'view', then it would invoke
ActionView().

--------------------------------------------------------------------------------

Output filtering:

The last stage of the request pipeline is output filtering. At this stage, the
HttpResponse is transformed into the body of the HTTP response.

If the HttpRequest has the X-Requested-With header, for example, the output
filter would know to respond with JSON. It could also look for other parameters
in the request (like ?format=xml) to determine the response encoding.

Template systems can hook in here, too. Actions can store arbitrary data in the
HttpResponse, including the name of a template in which to render the response
data. A simple templating system is included with Hoplite, but because the
model is represented entirely within the HttpResponse, other templating systems
can also be used freely.

--------------------------------------------------------------------------------

URL mapping:

There are two ways to map URLs to Actions. The first is prefix matching, which
assumes that all paths are relative to the URL of the RootController and do not
need to start with a slash. In this form, any substrings within {curly braces}
will be extracted as a variable by that name. The value will be placed in the
HttpRequest's data dictionary.

If the application were at:

  https://example.com/webapp/index.php

Requests will be in the rewritten form of:

  https://example.comm/webapp/user/view/42

The UrlMap could be any of the following:

  ID paramter extracted manually from the URL or through GET or POST variables
  'user/view'

  Using path parameter extraction
  'user/view/{id}'

  Using an ActionController (see previous section)
  'user/{action}'
  Or,
  'user/{action}/{id}'

In the above forms, the matcher does prefix matching. Combined with the fact
that rules are evaluated linearly, this can lead to a potentially unexpected
result. When you have a more general rule before a specific one, the general
will always be the one matched. For example:

  'document/edit'
  'document/edit/{id}'

The second rule will never be matched, because the evaluator will find and
invoke the first rule and then stop. This isn't always the desired behavior and
can be altered by adding two slashes to the end of a rule. These two slashes
make the parser matching strict equality, rather than prefix.

The second type of matching is done by regular expressions. These patterns both
start and end with a slash. They are evaluated every time a request is routed
and any pattern groups are saved in the url_pattern key of the HttpRequest data.

For example, the following could be used to match the above routes:

  '/user\/([a-z]+)(\/([0-9]*))?/'

About

The successor to phalanx

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published