Skip to end of metadata
Go to start of metadata

This document serves as several proposals combined, and consists of the
following:

  • An overview of various issues and requirements
  • Requirements (as bullet points)
  • Proposed Interfaces
  • Use Cases

The focus of this proposal is on the following:

  • Basic interfaces for the ZF2 MVC
  • How these interfaces may interact

It is not intended to discuss the following:

  • Where code will exist within the filesystem in projects
  • Final MVC implementations. We will create separate proposals for the default implementations once this proposal is accepted.

In this proposal, we are specifically keeping the following themes from the ZF2 requirements in mind:

  • General goals:
    • Easing the learning curve
    • Improving baseline performance
    • Make extending the framework (trivially) simple
  • Developer goals:
    • Programming by contract
    • Simplification
    • Favoring of the explicit

The primary takeaways from this proposal (or set of proposals) should be that the ZF2 MVC:

  • must be built with both simplicity and extensibility in mind.
  • should provide the basic building blocks for creating custom MVC layers; other systems utilizing those building blocks should retain compatibility with these systems and shipped implementations.
  • will provide a simple, standard MVC solution (though details on that will come in later proposals).

Overview

ZF's MVC has grown organically. While the basic, shipped MVC works for many, there are number of limitations that cause issues for those wanting to deviate from the standard workflow.

Page Controllers

In some cases, page controllers (vs. a front controller with many action controllers) are desired. In this paradigm, a separate end-point would be created for a particular controller (or multiple endpoints for multiple controllers), and it would then handle all requests to that end-point. (Page controllers were especially common pre-frameworks.)

Currently, ZF1 is not terribly friendly in this regard. While action controllers can be instantiated on their own, there are a number of soft dependencies on the front controller – e.g. redirects and URL generation typically require pulling the router from the front controller, layout rendering assumes a front controller plugin, etc. While many of these obstacles may be overcome, page controllers should be much easier to create than they currently are.

No Action Controller Interface

If you wish to attach a controller to the MVC, it must extend Zend_Controller_Action, as that's the type tested against, and provides the only blueprint or abstract implementation of a controller in the framework. This is problematic on many levels:

  • If you do not want the various features of Zend_Controller_Action – action helper integration, _forward(), _redirect(), front controller parameter injection, etc. – there's no way to disable that functionality, as it's baked in. You cannot simply substitute an alternate implementation.
  • If you want to alter how action dispatching works, you must fight both the dispatcher and the action controller.
    • The dispatcher sends an "action" argument to the action controller's dispatch() method – but it's actually a method name; you have to pull the actual action name from the request object. This means, again, fighting the framework. This smells of poor interface definition.
    • A number of developers and organizations have requested the ability to pass arguments to action controllers. This is actually possible – but, again, not easily achievable due to the structure of the framework. In this case, the abstract controller is too limiting for those extending the framework, and smells of restrictive interface definition.
    • If you want to use a different convention than <action>Action() for dispatchable methods, again, you must pull the action name from the request object. This makes it difficult to mix-in existing service objects and/or controllers from other MVC frameworks.

Basically, we need some sort of action controller interface that allows for both the default, defined use case, as well as alternate implementations to exist side-by-side.

Poorly Composed Responsibilities

Continuing on the subject of Zend_Controller_Action, the class currently has too many responsibilities:

  • View composition, initialization, and rendering
  • Redirection
  • Forwarding additional controllers
  • Helper broker (this is actually not terrible, as it composes the helper broker; however, access to the broker is not ideal)
  • Composition of application parameters
  • Hook management and lifecycle
  • Action dispatch

The base action controller interface should only define the minimum requirements for executing an action controller, and everything else should be either:

  • Composed in (either via controller or setter injection)
  • Part of application logic

At its basic level, an action controller is a Strategy or Command pattern – the front controller executes the action controller and returns a response. As such, anything outside that scope is likely suspect in terms of design.

Services

ZF1 created a number of server classes: AMF, JSON, XML-RPC, SOAP (we won't talk about REST). These all follow the PHP SoapServer API:

This API is simple and effective. We've discovered one or two limitations – it would be better to always require a request object to `handle()`, for instance, but overall, it works.

There are some cases, however, where the approach is limited:

  • Request/Response objects in the services are limited in functionality; if you need to set or get additional headers, you're on your own.
  • Authentication and Authorization are items often automated in the MVC – which leads to writing extra code for service endpoints in order to make use of these.
  • No hooks. Having the ability to tie into things like pre/post-handle would be useful for automating things such as authentication/authorization. Currently, while you can program around these, there's no easily re-usable, pluggable way of doing so.
  • Inability to configure; setting classes/objects/functions, request and response classes, etc. all must be done manually, instead of via options and/or configuration classes.

These often lead to developers wrapping services within the ZF MVC layer. This, however, leads to additional issues:

  • Each server is basically an MVC in its own right. This leads to duplication of objects (request, response), duplication of logic (dispatching controller + dispatching service), and degradation of performance (Often 5-20x better performance is had by using a standalone service).
  • No ties/hooks into MVC; you end up needing to disable things like layouts, views, etc. manually.

Making services capable of being configurable, first-class citizens of the MVC would simplify service creation and exposure within applications.

Dispatching

Zend_Controller_Dispatcher_Standard is, frankly, an atrocity. While a dispatcher interface is defined, the front controller, the dispatcher itself, and several other classes all utilize methods that are not part of the interface. This makes it incredibly difficult to drop in alternate dispatch mechanisms.

Why would you want to do that?

  • Micro-MVCs, or performance-optimized MVCs. Often, a business need may require performance optimizations that the default ZF MVC is simply incapable of providing.
  • Alternate controller strategies. If you don't want to follow the convention of <name>Controller::<name>Action(), you have to replace both the dispatcher and action controller strategies – and modifying the dispatcher is difficult.
    • One use case for changing the strategy is RESTful controllers. It doesn't make much sense to have separate actions for each request method – a switch statement and an interface for resources could accomplish this much more quickly.
    • If you replace the dispatcher mechanism, this means you cannot re-use action controllers between projects, as one may assume the standard dispatcher, the other a custom dispatcher.

In order to be re-usable, the dispatcher interface must contain only the methods necessary for dispatching, and a way to configure itself.

Too Many Hook Points

Right now, we have three layers of hooks within the ZF MVC (from outside -> in):

  • Front Controller plugins
  • Action Helper hooks
  • Action Controller hooks

One common issue on the ZF mailing lists is when and where to register automated processes. There are four answers:

  • Front Controller plugins, if they don't need to be aware of the action controller, and need to be run on every request.
  • Action Helper hooks, if they may need to be aware of the action controller, and likely need to be run on every request.
  • A base action controller extension class, in the init() or pre/postDispatch() hook methods, if action controller awareness must be present, and you want to selectively apply hooks to all or some controllers.
  • A specific action controller's hook methods, for ultimate specificity.

This presents a number of problems:

  • Education. Developers must learn the entire life cycle of the standard MVC in order to make good use of it.
  • Different mechanisms have different specificity. This can be a good thing, but it can also lead to edge cases quite quickly.
  • Each registers with the system in a different way.

Hooks:

  • must be standardized:
  • must allow opt-in behavior. One controller may require hooks, while another might not. An example: service end-points likely may not need view and layout automation, while normal controllers might.
  • must be implemented in a way that they may be composed in. In other words, neither front nor action controllers should require methods for registering hooks, but rather utilize a collaborator to do so. This allows easy mocking, the ability to setup hooks via extension classes, or runtime configurability.

Usage outside ZF applications

Related to page controllers, it's often useful to integrate Zend Framework within other systems, such as WordPress, Drupal, Joomla, TikiWiki, etc. These systems often provide hook systems that allow you to execute code on-demand. As many ZF applications may utilize a full variety of MVC features, including views, request and response headers, etc., embedding and wrapping the ZF MVC within hooks can be an expedient way to accomplish this task. However, this tends to:

  • introduce negative performance impact
  • introduce complicated configuration and setup

Wrapping ZF MVC functionality should be easy to accomplish.

Alternate View Strategies

Currently, ZF only offers a single view strategy, based on using PHP as a template language. Alternate view strategies may be utilized by implementing Zend_View_Interface, but, as with the dispatcher, many methods assume and call more functionality than the view interface defines.

Additionally, some strategies are not easily supported:

  • "Code-Behind". In this paradigm, individual template pages are called by the front controller, and the templates "wire in" code that will handle specific events, usually through tags:

    This would load the appropriate file, inherit code, and execute it. Currently, this sort of strategy is impossible without introducing an entirely new MVC layer.

  • Hierarchical MVC. HMVC's primary strength is that it allows for creation of complex content by executing many different MVC triads. As an example, a call to one controller may initiate calls to two additional controllers, each of which may also execute additional controllers; the results will then be aggregated and passed to a view. This is different than "forwarding" in the current system, as the entire request/response cycle of a given controller happens within the body of a single action. This allows manipulating the response to determine what is relevant to the current request.
  • Strict segregation of templates from development. The default MVC keeps all view scripts under the same tree as the given module. This means that it's more difficult to segregate access easily for designers. Often, it would be easier to put all view scripts for the entire application under a single directory, and give designers access only to that directory. While possible with the view renderer, it's non-trivial.
    • Additionally, using PHP as the templating language is not optimal for many designers; the ability to utilize a standard template engine would often be easier for purposes of training.
  • Transform views are not supported currently. Transform views are an alternative to Two Step Views, and often simpler for designers to utilize.

Configuration and Injection of Resources

How do resources make their way into controllers, views, etc.? This question was largely answered in ZF1 with the introduction of Zend_Application. However, this integration is incomplete.

  • The bootstrap is injected into the front controller singleton
  • The front controller injects the bootstrap into controllers
  • All other classes retrieve the bootstrap from the front controller singleton

Two solutions present themselves:

  • A dependency injection container
  • A service locator

Either solution is possible with the current implementation of Zend_Application_Bootstrap; it does not specify what type of "container" is used internally.

The question is fundamentally this, however: how should controllers, models, and views get their dependencies/resources? Should we expect the front controller/dispatcher to inject them, or to pass a service locator to them so that they may pull them themselves?

Alternately, should the ZF MVC interfaces care?

Performance

ZF's MVC performance has (mostly) steadily declined since the 1.0 release (with the exception of the 1.7 release, when a performance audit was performed). In large part, this is due to additional functionality:

  • Adding layouts added another view rendering phase to the typical request
  • Adding Zend_Application and the bootstrap lifecycle

In performance profiling, the ZF team has discovered that the primary source of the bottlenecks is in the !PluginLoader implementation, which (a) has many stat calls, (b) doesn't cache between instances, and (c) differs between components. We have done a large amount of work during the Autoloading & Plugin Loading milestone to correct this situation, but are looking for additional areas we can improve performance in the MVC layer.

Modules

The current approach to modules in ZF is very much "tacked on". Due to how they work, it's quite difficult to simply "drop in" third-party code and expect it to work. While this is somewhat better since the introduction of Zend_Application, the requirement to execute a bootstrap for each module that requires autoloading leads to additional performance degradation.

Modules should be considered "first-class citizens" of Zend Framework.

Requirements

  • Basics
    • The basic building blocks of the MVC must include standard Request and Response interfaces.
      • The default implementation must provide HTTP-aware implementations of the Request and Response interfaces.
    • The basic responsibility of the MVC and Server classes must be to convert a Request object into a Response object.
    • The primary goals are to:
      • Create interfaces and loosely coupled objects for creating MVC implementations; and
      • Create one or more default implementations.
  • Request object
    • Must handle both request metadata and optionally content.
    • Must provide an HTTP-aware Request implementation:
      • Aware of Request-Method
      • Aware of Superglobals ($_GET, $_POST, $_SERVER, $_ENV, $_FILES, cookies, sessions, etc.)
      • Aware of HTTP request headers
      • Should be aware enough of Content-Type and Request-Method to be able to auto-populate $_PUT and $_POST from the raw request body for any format supported by Zend\Serializer.
  • Response object
    • Must handle both response content an optionally metadata.
    • Must provide an HTTP-aware Response implementation:
      • Must be capable of aggregating and emitting HTTP response headers and status codes.
      • Should be capable of manipulating Cache-Control headers
      • Should be capable of aggregating and emitting cookies
      • Might be "View-aware", such that getting a View Model or View Renderer as the content would auto-render the view when the response is emitted.
  • Headers
    • Must provide interfaces and implementations for representing invidivual HTTP headers as well as collections of headers
  • Cookies
    • Should provide interfaces and implementations for representing cookies and collections of cookies
  • Parameters
    • Must provide interfaces and implementations for representing metadata objects (including the superglobals).
    • The Parameters interface must allow for array access of metadata.
  • Page Controllers:
    • Must be able to create page controllers with ZF.
    • Must be able to utilize page controllers outside the front controller paradigm.
    • URL generation should be de-coupled from the front controller
    • Controller "redirection" and/or "forwarding" must be de-coupled from the front controller
    • Must be able to configure services/resources and inject easily, preferably via the constructor.
    • Ideally, Action Controllers should be re-usable as standalone Page controllers.
  • Action Controllers
    • ZF2 must offer a simple, strong interface for action controllers.
      • The action controller interface must not require front controller interaction.
      • Action controller dependencies must be injectable, either through explicit setters or the constructor; the interface should not dictate anything that would prevent this.
      • The action controller interface must specify a single method for dispatching itself.
    • Action controllers must allow the flexibility to re-define the conventions for resolving actions.
      • ZF2 must offer a default implementation with the recommended convention
    • Action controllers must allow the flexibility to determine whether or not action methods will expect arguments.
    • Action controllers should optionally allow lifecycle management, preferably via signal slots and/or action helpers.
      • The default implementation should allow configuring lifecycle management both statically and via constructor injection.
  • Server classes
    • Must implement the same basic interface as action controllers, in order to allow them to be composed as part of an MVC application.
    • Must utilize the same base Request and Response interfaces, and should decorate these in order to allow de/serialization of the protocol format.
    • Should provide lifecycle hooks, likely in the form of !SignalSlots.
      • Hooks should be injectable/configurable
      • Hooks should allow static configuration as well as per-instance.
      • Hooks for servers should not utilize the same signals as action controllers, to help prevent things such as View/Layout injection.
  • Router
    • The basic "Route" interface must:
      • Provide the ability to match a Request object to metadata tokens.
      • Provide the ability to assemble a URL/Request based on metadata.
    • A new "RouteStack" interface should be developed, allowing the ability to provide a stack of routes to test for matches.
    • Routing could write matched metadata to the Request object metadata.
      • This is under debate. However, doing so would simplify most workflows for the MVC. The main question is whether this should overwrite such metadata, or whether the RouteStack implementation would return a "RouteResult" object that it would then register as a single metadatum of the result.
  • Dispatcher
    • Must follow the same basic interface as action controllers and server implementations.
    • The dispatcher must be responsible for mapping a controller name to a class that will handle it, and optionally injecting configuration.
    • The dispatcher may be omitted, depending on the MVC created.
    • Should return a response as soon as it has one.
  • Front Controller
    • Must not implement a singleton pattern.
    • Should be responsible simply for:
      • Router management
      • Dispatcher management
      • Dispatching the request
    • Application Configuration should be injected into the child objects.
    • Should provide lifecycle hooks around the router and dispatcher.
    • Should return a response as soon as it has one.
  • Lifecycle hooks
    • All areas where hooks are used must use the same mechanism
    • In most cases, static configuration as well as per-instance configuration should be supported.
  • Application configuration
    • Application-wide (or commonly used) resources must be configurable
    • Dispatchable objects (controllers, dispatchers, servers, etc.) should accept application configuration, and "wire themselves" based on that configuration.
    • Configuration management must handle dependencies.
    • Configuration management must lazy load when requested (i.e., it should not preload all resources)
  • Performance
    • Performance of the MVC layer must be as fast as possible, while still supporting required features such as layouts, lifecycle management, and application configuration.
  • Modules
    • Design of any shipped MVC implementations must encourage module re-use, and must support modules as basic MVC infrastructure.

Proposed Interfaces

In examining the requirements, a standard interface for page/action controllers, dispatchers, service providers, and front controllers emerged, essentially a Command pattern:

Basically, by making each of these components "dispatchable", we get a number of advantages:

  • Controllers may be used either standalone, or within a larger application context (cronjobs, message handlers that consume controllers, etc.). This provides the ability to create standalone page controllers,
  • Server classes may be configured and attached to a front controller. In this case, they can become first-class citizens of the MVC, instead of something tacked on or wrapped.
  • A front controller implementation need only offer the ability to broker controllers to dispatch. This leads to the ability to slipstream custom implementations that are tuned for specific needs.

To this end, we propose the following interfaces:

  • Message interface (metadata and body content)
  • Request interface (extends Message)
  • Response interface (extends Message, provides a way to emit itself)
  • Dispatchable interface (takes a Request object, and optimally returns a Response object)
  • Route interface (takes a request, and decomposes it into a Result)

The basic use case then becomes:

Interfaces

Interface definitions have been written and committed to the following repository:

with concrete implementations in the "Zend" tree of the "feature/zf-implementation" branch. Below are the basic definitions.

  • Message
  • Request
  • Response
  • Dispatchable

Additionally, HTTP-aware versions of the Request and Response interfaces are proposed:

  • HttpRequest
  • ModifiableHttpRequest
  • Uri
  • HttpResponse
  • HttpHeaders
  • HttpHeader
  • HttpRequestHeaders
  • HttpResponseHeaders
  • HttpStatus
  • Parameters

Routing is an aspect of the MVC that would be affected by these interfaces. The following interfaces would be used within the routing subcomponent:

  • Route
  • RouteStack

Use Cases

The following are examples covering a variety of use cases.

We are discussing currently what exact form $options will take. It will be a service locator of some sort; we are split on whether it will also be a dependency injection container (even if we don't, we will likely make the definition flexible enough to allow using one). For now, focus on the use cases surrounding the interfaces.

Page Controller

One often requested feature is the ability to use action controllers as standalone page controllers. As the Dispatchable interface simply requires that a Request object be passed, this becomes a trivial use case.

Front Controller

The Zend Framework 1.0 front controller is actually relatively simple. It's dispatch() method currently simply routes and then dispatches the request. That paradigm could be used again to provide a simple ZF1 emulation layer:

In the above, the assumption is that $options would contain dependencies – such as a dispatcher, router, etc – and that these would be configured as well. The dispatcher would look like this:

In other words, it, too, would implement the Dispatchable interface, and be responsible for determining what Dispatchable objects attached to it should be invoked.

This leaves great flexibility of implementation – anything Dispatchable can be used as an action controller.

Internally, plugins would be swapped out in favor of SignalSlots, giving some additional flexibility of implementation, as well as simplifying the front controller implementation.

Basically, the front controller would simply become a Facade for managing the workflow of other objects.

Server Classes

ZF currently provides a number of Server classes: Zend_Json_Server, Zend_XmlRpc_Server, Zend_Amf_Server, etc. These would all follow the same interface:

These would likely use either extensions to the base Request/Response classes provided, or decorate them in order to provide de/serialization of the protocol for which they are responsible. (Decoration offers the most flexibility for differing use cases.)

Because they implement Dispatchable, they could be mixed in as just another dispatchable within a Front Controller implementation, or executed in standalone endpoints:

Micro or Custom MVC stacks

When dealing with either small sites, or large sites with specific performance requirements, rolling a custom MVC stack is often useful. The current ZF1 implementation does not make this easy. The proposed interfaces do, however. Consider the following, callback-oriented dispatcher implementation:

Don't worry about the various objects referenced; the main thing to understand is that it's using those same MVC building blocks: Request, Response, Dispatchable. In action, it looks like this:

The same MVC building blocks are combined in this example to produce something that looks quite different from the ZF1 MVC – yet can pick and choose pieces from the ZF2 MVC and interact with them in a standard way.

Using Traits instead of inheritance

Due to the simple nature of the Dispatchable interface, it lends itself well to PHP 5.next's traits features. As an example, a "REST" trait could be mixed in to a class quite easily to create a REST controller.

While ZF2 will target PHP 5.3, we can also potentially provide ready-made traits for those using PHP 5.next. This will help simplify development for end users.

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Dec 22, 2010

    Some quick comments on the subject matter that are not explicitly stated but should be:

    1. Configuration and Injection of Resources
      • I would go with a Service Locator as it would allow the most flexibility in terms of the concrete implementation to fetch what it may or may not need without the need to largely inject what is needed. Since the configuration and injection of these resources should likely be consistent AND expected in terms of development, it would make sense to utilize the Service Locator as it would be a dependency at this point in time thus enforcing it would be available for folks that are adding on in the future with little additional work which would also keep performance slightly faster when looking up several different items.
    2. Request and Response objects must not be completely tied to HTTP requests.
      • CLI is a perfect example of this where $_SERVER is for HTTP as $_ENV is mainly for CLI
      • The implementations of Request and Response is largely different depending on the implementation throughout the current ZF 1 and should largely be tied to Request objects that can be of any type that implement that interface.
      • Some good examples of this are thing such as implementing a Gearman Wrapper - you want to display jobs based off of the CLI and be able to inject them that way. This is also where a Page Controller would help explicitly.
    1. Dec 28, 2010

      1. I'm definitely leaning towards a Service Locator that implements lazy loading. As you note, it would reduce the amount of overhead necessary during application initialization to only what is needed for that particular controller. (Symfony 2 even invokes this same paradigm, passing the service pull the dependencies they need.) locator – which contains the DI container – to controllers so that they may
      2. There is no intention to tie the Request and Response objects to HTTP. If you look at the interfaces, the most basic versions are not HTTP aware, and HTTP awareness is provided by implementing specific interfaces. The idea is that for controllers you wish to re-use in different contexts, you would program towards the most compatible interface.

      Thanks for your input!

  2. Dec 22, 2010

    I'm not sure if we can discuss all the interfaces without discussing the behavior, having said that...

    The basic building blocks of the MVC must include standard Request and Response interfaces.

    Is by that meant interfaces that are shared/used across several frameworks (ZF, symfony, etc)?

    What do you understand by both Action Controllers and Page Controllers, what purpose do they suite, and how do they differ?

    Application-wide (or commonly used) resources must be configurable

    Imho, once done initializing (bootstrapping) we shouldn't allow for further configuration.

    I skimmed over the page quickly, so I'm sorry if I missed something (will look at it more closely later)

    1. Dec 28, 2010

      Is by that meant interfaces that are shared/used across several frameworks (ZF, symfony, etc)?

      Potentially. Fabien Potencier, lead for the Symfony project, discussed this idea with me at ZendCon, and I began work on defining shared interfaces. However, we have not at this point solidified any plans in this direction.

      The point of the wording is that we will explicitly define interfaces for Request and Response objects, and that these will be used across the framework – both in the MVC (where they may be used for both HTTP and CLI requests), as well as in server components (which are a form of MVC, with the presentation format strictly defined) and service clients (HTTP client, REST client, etc.).

      "Application-wide (or commonly used) resources must be configurable." Imho, once done initializing (bootstrapping) we shouldn't allow for further configuration.

      I wasn't trying to imply differently.

      1. Jan 18, 2011

        With time closing in on finalizing the proposal, has any additional effort been given to coming up with cross library interfaces? I think both communities have some outstanding people working with/for them, so any ability to leverage more resources has the potential to benefit all involved.

        That said, I completely understand that getting two projects coordinated is an incredibly difficult tasks since both will be on different release schedules and may have licensing/ownership issues, etc.

  3. Dec 22, 2010

    On last example I see you are using a request object of Zend\Http component.
    1. Will Zend\Http\Request be similar to Zend_Http_Client of zf1 now also used on mvc ?
    2. If yes, we'll have to fill the request object with current data (get, post & friend)
    or how to create an own request with own data to send an own request to a remote server ?

    1. Dec 28, 2010

      1. Zend\Http\Request would be an HTTP-specific Request implementation – and would be used in both the MVC, as well as Zend\Http\Client.
      2. The request would not have an emit() method – the client would.
  4. Dec 22, 2010

    At a glance there seems to be something smelly going on in the last code sample.

    There seems to be no relation between the Router and Dispatcher.

    I guess the Router is mutating the Request object somehow, and I don't particularly like that idea. As it means the Request has to go via a Router first, or some some magic has to alter the Request first before being dispatched.

    Either passing the Router to the dispatcher, or the dispatcher to the router, and making the request immutable would be more preferable maybe (requires more thought)

    1. Dec 23, 2010

      As written, we still have to discuss whether the router should manipulate the request object or not. I personally feel better to return the RouteResult object, as I dislike to have the router manipulate the request, but this could be a problem with an event driven dispatcher implementation.

      1. Dec 23, 2010

        Another option would be for the router to decorate the original request with say a DispatchableRequest interface.

        1. Dec 24, 2010

          Mh, decorating... reminds me of christmas trees

        2. Dec 28, 2010

          This is the route (pardon the pun!) I'd like to take. The reason being that passing just a request object to a dispatcher simplifies a number of workflows. As an example, I worked on an event-oriented dispatcher at one point, which made it difficult to allow different return values – it was much simpler to simply pass each event the request object.

          This would be fairly simple – DispatchableRequest would simply define two methods:

          1. Jan 05, 2011

            I am also think that it is a good idea.

          2. Jan 10, 2011

            After more thought I think the Request object should be immutable.
            I cannot see why you would need to access the RouteResult more than once (just to dispatch it).

            Having the Request immutable allows you to cache the RouteResult per Request by decorating the Router instead.

            Something like this...

  5. Dec 23, 2010

    "Hierarchical MVC. HMVC's primary strength is that it allows for creation of complex content by executing many different MVC triads."

    This would be just great.

    Exactly my problem ATM.

    1. Dec 27, 2010

      HMVCs seem quite compelling but also demanding.

      Quite a good article here I thought: http://techportal.ibuildings.com/2010/02/22/scaling-web-applications-with-hmvc/

      ...and a follow up to it optimising with caching and even (to an extent) asynchronous processing: http://techportal.ibuildings.com/2010/11/16/optimising-hmvc-web-applications-for-performance/

      1. Dec 28, 2010

        They can be demanding, but a number of developers have created such implementations in ZF – and wished that the structure of the framework was such that it more easily facilitated such endeavors.

        As such, my hope is that the proposed interfaces can accomplish this.

      2. Jan 08, 2011

        I noticed that the PECL extension HttpRequestPool (http://www.php.net/manual/en/class.httprequestpool.php) is being used in that second article. Perhaps an implementation of this can be included with the new MVC also?

  6. Dec 23, 2010

    Generally speaking the interfaces look quite good. But the HttpResponseHeaders interface is bloated a little bit. For testing the header status wouldn't it be better to do some chaining like:

    Furthermore there are some inconsistencies like the sent() method. Shouldn't it be named isSent(), wasSent() or something like that?

    1. Dec 28, 2010

      These are great suggestions, and I plan to incorporate them.

      I chose "sent()" for its brevity – but since we don't have a "?" operator for testing booleans in PHP, you're right – "isSent()" makes more sense.

  7. Dec 25, 2010

    This is looking good overall. A few notes:

    >> Routing could write matched metadata to the Request object metadata.

    I would like to see the request object as immutable.

    >> Application Configuration should be injected into the child objects.

    Excellent.

    >> Application-wide (or commonly used) resources must be configurable

    It would be helpful if these always needed a key prefix (assuming a similar style to resources.*) so > 1 of each resource could be configured. For instance, it is often necessarily to have two mail objects configured differently. Of course, this can be done today with a bit of massaging; however, a consistent and supported API would be a bit nicer.

    >> Design of any shipped MVC implementations must encourage module re-use, and must support modules as basic MVC infrastructure.

    Are we talking in terms of Symfony "bundles" and Rails Engines or are we talking about the current nomenclature of a module as a directory of controllers? I'm hoping we are talking about the former as I believe the latter can be more cleanly handled with routing and namespaces.

    1. Dec 28, 2010

      I would like to see the request object as immutable.

      This is a no-go for me – making it immutable makes testing more difficult (need to use different implementations for testing than you do for the application), and also means it cannot be used easily in other contexts (server classes, where the request would be decorated in order to deserialize the request to PHP data structures).

      For instance, it is often necessarily[sic] to have two mail objects configured differently.

      I'd argue for situations like these, you either create a "manager" object, or we ship one in the framework (much as we've done for cache, log, DB, etc.). That makes the story of having multiple related resources simpler, and more easily configurable.

      Are we talking in terms of Symfony "bundles" and Rails Engines or are we talking about the current nomenclature of a module as a directory of controllers?

      Definitely the former – the idea is self-contained functionality, which would require controllers, models, views, all resources, etc. to enable that module to work.

      (This was the goal of modules in ZF1, and partly realized with Zend_Application, but the idea is to be more explicit with ZF2.)

      1. Dec 29, 2010

        making it immutable makes testing more difficult (need to use different implementations for testing than you do for the application)...

        I can appreciate this stance; however, I would argue that it would probably be better to test based on the interface which would allow 1..N implementations?

        ...it cannot be used easily in other contexts (server classes, where the request would be decorated in order to deserialize the request to PHP data structures).

        If this truly is the deal breaker, then I would have to agree with your stance.

        you either create a "manager" object, or we ship one in the framework

        Fair enough

        Definitely the former - the idea is self-contained functionality, which would require controllers, models, views, all resources, etc. to enable that module to work.

        This is good.

  8. Jan 03, 2011

    I would like to see the "Message" interface as an implementation of Serializable. Since the message object is at the main tier there is an extreme amount of usage for this object. It would be quite easy to extend this on our own, however, there is quite a bit of usage specifically for it to be an implementation of serializable by default.

    For instance:

    • Flash Messaging
    • JSON Payloads
    • Apple APNS Payloads (meta data could contain implementation for the specific keys)
    • Google C2DM Payloads
    • Previous request methods

    Also with the "Message" interface, I am unsure about the following methods:

    public function setContent($content);
    public function getContent($content);

    Is this meant to be an array going to set for content? Or a method to set just a string of body content? Not sure what get is supposed to do while taking a parameter... maybe a typo?

    1. Jan 03, 2011

      re: Message being Serializable – good point, and I think that makes sense.

      re: setContent/getContent(). First, I've now updated the proposal to remove the argument to getContent(); it was indeed a typo. As for what $content should be, I specifically didn't typehint it, to allow flexibility in what the argument may be. This will allow passing a string, an array, an object – it would be up to the individual implementations to determine what valid content might be for a message.

  9. Jan 04, 2011

    Regarding the

    The question is fundamentally this, however: how should controllers, models, and views get their dependencies/resources? Should we expect the front controller/dispatcher to inject them, or to pass a service locator to them so that they may pull them themselves?

    I believe that passing the service locator or DI container into controllers, and views would make the code in the controller/view easier to understand since the service needed for the execution would be in the same place they are needed.

    Not sure though if this would have an impact on unit testing controllers.

    I really love the idea about Hierarchical MVC. And if I understood correctly it would be possible to create an implementation of ESI quite trivial. A had a look at Symfony 2 ESI implementation and this is maybe the most important feature I would like to see done well in ZF2 because fetching parts of the page from memory at the reverse proxy level is order of magnitude faster that hitting the application on every request.

    1. Jan 17, 2011

      I'm definitely interested in investigating ESI for ZF2; I can't tell you how many times the "personalization problem" has bit me, and ESI definitely provides a solid solution for it. Right now, however, that investigation is a bit further down the line in the milestone.

  10. Jan 09, 2011

    I was wondering if the Response object should also be Dispatchable?

    The Dispatcher::dispatch method could then keep dispatching until either Request::isDispatched() (or similar) is true or the maximum number of dispatches allowed is reached.

    The return type of the dispatch method could then be null or another Dispatchable object.

    1. Jan 17, 2011

      While I see the elegance of this approach, I also worry that a semi-recursive structure like this would lead to difficulty in debugging and learning the framework. That said, since we can't type-hint on the return value, we could certainly check for a Dispatchable return and execute it.

  11. Jan 11, 2011

    The HttpResponse interface is currently sending the headers to the client by usage of Sendheaders and Sendcontent. Wouldn't it be better to change the methods to getHeaders and getContent? Because it not always clear where you want send the headers and content. Maybe you would want to log the headers and content?

    Furthermore, the HTTPResponse Interface should also be usable for Zend\Http\Client ( or the ZF2 equivalent )

    The same applies to HTTPRequest & HTTPRequestHeader & HTTPResponseHeader

    Furthermore the great number of isValid, isEmpty, is* is confusing, and should be reduced to a more normal limit

    delete:

    • isOk the isSuccesfull should be enough for most cases
    • isInformational not many people will ever need this.
    • isEmpty
    • isServerError, isInvalid and isClientError should be combined in isError. People are most interested if it was succesfull or not. If people need more information, they can easily get this from getStatus.
    1. Jan 17, 2011

      HttpResponse has both get(Headers|Content) methods as well as send(Headers|Content) methods. Sending the response is done with emit() (defined in the base Response interface).

      Regarding the various response status testers, another commenter had a good idea: move the status into its own object. This allows us to trim down the HttpResponse interface, while still having a rich interface for testing status.

      I agree that we should have an isError() method – but this shouldn't rule out the more specific tests.

  12. Jan 19, 2011

    I like the suggestion for trait in dispatch. Good new PHP feature!

    I've looked at Kohana and Alloy frameworks in respect of HMVC. I think I get it.

    Would like to suggest the view interface provides for a view-html-header object which is accessible to every (cloned) instance of view for each triad. What I mean is you can mess with the current instance of view and you can also call on it to change the unique state the view-header object. I don't think view has been addressed yet fully.

    I still don't see the justification for a Zend_Application or a front controller - sorry. Better to create a Zend Core that also provides the signal-slot pattern for all classes extending it and then also provide resource grabbing such that based on the config, somehow you just call a resource as needed from anywhere and you get it

    If magic methods are undesirable it's getResource('request'), getResource('log') etc. and all lazy loaded in the core class of course - like a kernel for everything but not a singleton unless it has to be.

    In fact if every class extended a core class there would be no need for any singletons at all. Is that good or bad testing-wise? Perhaps convenience methods for the most often called resources?

    I'm still not sure how modularity would work for that but, perhaps a search list of resources in place of a namespacing would be okay if constants provided a convention for those common resources we all use? I like the idea of everything being a resource to simply call and not existing until referenced.

    Is there any chance of a changing demo showing HMVC capability? Nothing fancy, just flesh on the bones as I seem to be a learn-by-example type and would like to know the ZF2 interpretation re: PAC/HMVC on Wikipedia. Can the view call a new MVC triad for example? I hope so, but not assume the view can access the model.

    Finally the caching. Caching specific parts of the output seems ideal to me - as much or little as you want of the output - so it should be a stage before each MVC call I think and using existing HTTP standards as per: http://docs.symfony-reloaded.org/guides/cache/http.html#using-edge-side-includes

    1. Jan 28, 2011

      Mark, thank you for the very good article

      Within this proposal I don't understand the difference of the following methods of HttpResponseHeaders: (setExpires and setMaxAge will set the headers but what does the others ?)

      Another question is why does the method "HttpResponseHeaders::isNotModified" need a Request object as parameter?

      By the way it would be helpful to auto-generate cached responses by storing the sent response locally

      • cache only on GET/HEAD requests
      • cache only 200 responses
      • generate cache id in base of request
        (URI + Vary-Headers ...)
      • generate ETag in base of response (if not present)
      • generate Last-Modified by mtime of cached item (if not present)
      • create 304 response if:
        • response was cached before
        • ETag of cached response matches requested If-None-Match
        • Last-Modified of cached response matches requested If-None-Match
      • create 412 response if:
        • ETag of cached response doesn't match requested If-Match
        • Last-Modified of cached response doesn't match requested If-Unmodified-Since

      Now you can also send a cached raw response if the client doesn't cached this resource before.

      Please correct me if I'm wrong.

  13. Jan 19, 2011

    PS. If you don't want to cache by time-out you cache when it reaches the controller based on DB change and I guess handle that manually.

  14. Feb 05, 2011

    Community Review Team Recommendation
    At this stage we accept this proposal, and suggest moving forward to implementing it. The CR-Team recognizes that when problems arise while implementing the interfaces, it may be possible to slightly deviate from this proposal (when discussed with the community).