Hi, Here my review of the mvc tools docs. Keep in mind that I have not read _any_ of the discussions concerning this component before reading the requirements and the design doc. I will probably comment on things that have been discussed and things that are clear for everyone except me :)
Here goes the requirements review: > eZ Component: MvcTools, Requirements > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > :Author: James Pic, Tobias Schlitt > :Revision: $Revision$ > :Date: $Date$ > > Target and scope > ================ > > The scope of this document is to describe the requirements for a component > providing classes to implement a MVC_ architecture for a web application. > This document does not describe the design of the named component, but only > summarizes the requirements for it as discussed on the developer mailing > list. > Where suitable, design related topics will be touched, but a dedicated > design document will follow later, defining APIs, classes and the > architectural structure of the component. > > Note that if you don't understand a term, you should have a look at the > section `Clarification of terms`_. > > Introduction > ============ > > Model-View-Controller (MVC) is a common architecture pattern to implement > all kinds of applications using the object-oriented design paradigm. The > goal of the MvcTools component is to give users a basis for such > architectures for web applications written in PHP 5. The component shall > not provide a full- featured implementation of the MVC architecture, but > should help users to easily create their own, custom implementations. > > A good starting point to learn more about MVC is the Wikipedia article: > http://en.wikipedia.org/wiki/Model-view-controller > > Component integration > ===================== > > eZ Components already provide some components that are useful when > implementing an MVC. However, one basic goal of eZ Components is to keep > each component as independent as possible and to realize dependencies > through so-called tie-in components. Therefore the mechanisms realized in > an MVC component should be that far abstracted, that other components can > be tied in and provide only very basic implementations on its own. This > also allows users to implement their own mechanisms. The following > components have been identified as possible tie-ins: > > - EventLog_ (error-handling) > - Mail_ (error-handling, view) > - PersistentObject_ (models) > - Template_ (view) > - Tree_ (routing) > - Url_ (routing) > - UserInput_ (routing) > > .. _UserInput: http://ezcomponents.org/docs/tutorials/UserInput > .. _Url: http://ezcomponents.org/docs/tutorials/Url > .. _PersistentObject: > http://ezcomponents.org/docs/tutorials/PersistentObject .. _EventLog: > http://ezcomponents.org/docs/tutorials/EventLog > .. _Mail: http://ezcomponents.org/docs/tutorials/Mail > .. _Tree: http://ezcomponents.org/docs/tutorials/Tree > > For each of these components a tie-in component could considered to be > implemented at a later stage. This should be kept in mind when designing > the classes/interfaces for the MvcTools component. > > Design requirements > =================== > > This section summarizes the requirements regarding the later following > design document. > > Layers > ------ > > The MvcTools component should distinguish certain layers to allow users to > easily adjust and replace certain functionality. Therefore, the following > requirements have been specified. > > Controllers process and respond to events, typically user actions, and > may invoke changes on the model. > In a case, controllers run an action using a single argument: an > input-object, or a request object. > A controller returns an result-object after being run. > > Another different layer is responsible to select the controller to run and > the action to call on it. To create the request-object it requires the > so-called request parser. After the controller has been run, the result > object is send to the view-manager, which is responsible to select the > correct rendering mode for the output protocol/format. > > The request object is responsible of generating an input object, which > contains data that is not specific on the protocol; it can be used in > protocol-independent controllers. > > Those two layers use one controller per request. > They handle the client-protocol, so that the controller doesn't have work > on raw input data (e.g. GET/POST/...) and does not have to generate any > specific output format (e.g. HTML, XML, plain text,...) or anything that is > protocol-specific. The two layers abstract I/O from the controller as > described in the specific section. > > Summary > ^^^^^^^ > > - One controller and action can be run in one request. > - Controllers should neither work on raw input directly, nor create a > specific kind of result, but should only work on abstracted response and > result objects. > - Protocol dependent controllers may access the raw data. > - It should be straight forward to test any action. > > Ideas > ^^^^^ > > A PersistentObject_ tie-in could be supplied to easily realize Crud_ > controllers. > > .. _PersistentObject: > http://ezcomponents.org/docs/tutorials/PersistentObject .. _Crud: > http://en.wikipedia.org/wiki/Create%2C_read%2C_update_and_delete > > Request parser > -------------- > > Requests should be parsed by the request parser. > The request parsers are protocol dependent, and return a request object. > The request object in question is responsible for generating an abstract > input object, for controllers that are not protocol dependant. Is this right? In the design doc I get the feeling that the request object _is_ the abstract input. Or am I wrong? > The request parser is the first layer in action, it's possible to run any > controller with it's resulting request object, and protocol independant > controllers with the input-object resulting from the request object. > It handles input parsing and filtering, but delegates input validation to > the controller. Here is the first time filtering comes up but it is not explained. What is filtering? > Summary > ^^^^^^^ > > - The request parser is responsible to filter the incoming request and to > extract all relevant data into the request object. > - The request object is responsible to produce an abstract input object. If it is indeed three step (e.g request parser->request object->abstract input object) why is this so? Why doesn't the request parser generate the abstract input object right away? > Multilevel I/O abstraction > --------------------------- > > Modern applications often require to deal with different input and output > protocols and formats (for example HTTP-GET, HTTP-POST, SOAP for the input > part and HTML, PDF, ReST-webservices for the output part). > Therefore, it should be possible to use abstracted input and output > formats, into dedicated objects; which are not specific to a certain > protocol or format. > > Controllers will however receive all the input data, besides the abstracted > data that comes in from the request. It's up to the developer to make sure > none of the protocol-specific data is used in case he wants a > protocol-abstract controller. This allows protocol-specific controllers to > access the raw request data. > > The request-object contains all the request data. > > A beneficial side-effect relates to controller-testing: Creating request > and result mocks and fixtures allows straight-forward TDD. > > Summary > ^^^^^^^ > > - Some controllers should not know about the input and output environment > out work on abstract objects only. > - Protocol dependent controllers should have access to all the request > data. > > Routing > ------- > > Each request runs a controller. A controller returns an abstract value > that should be usable with any output formats and protocols. > > The router selects the controller to run. Controllers can call the routers > re-routing method with redefined input data to redirect processing to a > different controller. > > Routers must also provide a mechanism to create URLs from request-objects, > that may be used to access a certain controller and action with a certain > view-manager and defined parameters. This method must be accessible from > the controllers and the view-manager. Protocol independent routers can use > the input-object instead. Why is this mechanism needed? General questions I had about routers at this point: - who decides which router to use? - who calls the initial methods on the router? > Summary > ^^^^^^^ > > Routers are responsible for: > > - Selecting controllers based on the input > - Running the controller and collecting either the request object or the > abstract input object. > > Routers may be asked by a controller to re-route the request to another > controller and must therefore be accessible from any action. > > Tie-in components for the Url_ and UserInput_ components should be > provided to realize routers. The design of these components should be > considered important while designing the MvcTools component. > > .. _UserInput: http://ezcomponents.org/docs/tutorials/UserInput > .. _Url: http://ezcomponents.org/docs/tutorials/Url > > Controller > ---------- > > Controllers provide the actions that implement the business logic of the First mention of action? What is an action? (See comment on Action further down) > application. The controllers accept the request object as input. Each > controller implementation can provide two methods that provide filter Why two? > chains. These filter chains are run before - on the request object - and > after - on the result object to implement application specific filtering. I'm still not certain what this filtering is for. > It is left to the user on how the interaction with the model happens. There > are two basic options. One is where the model is directly used in the > controller through f.e. the PersistentObjectSession's singleton pattern. > The second possibility is to depend on a service interface. This service > interface then uses the PersistentSession to query, and work on the model. > This service interface architecture prevents the controller from being > dependent on the model. > > Summary > ^^^^^^^ > > - Controllers are user-implemented > - Controllers allow pre-run request filters > - Controllers allow post-run result filters > - There are two ways of dealing with a model > > View-management > --------------- > > Controllers return a value that cannot be send directly to the client > (abstract result object). Another layer uses the return value and processes > it into a specific response. This layer is called the view-manager. > > The view manager receives the result object and the abstract request object Is this the same as the abstract input object described earlier? I'm slightly confused :) > an can decide on the base of both of them which view handler to use. > > The view handler is responsible for rendering one or several result-objects > into a proper response. When can you have several result objects? How do you handle ordering? > Only one view-handler can be used to generate a certain response. It can > receive any number of abstract result objects. A view-handler is > responsible to render a certain output format for a certain protocol. The > view-handler to use is determined by the used view-manager. How does the view-manager determine this? > > For example, the view-handler that generate HTML/HTTP-responses is > separated from the view-handler that generates XML/HTTP-response. > > Summary > ^^^^^^^ > > View-manager role: > > - Receives the request object and the abstract result objects > - Builds the concrete response and sends it to the client > > A tie-in for the Template_ component should be provided with the first > release of MvcTools. > > .. _Template: http://ezcomponents.org/docs/tutorials/Url > > Error-handling > -------------- > > During debugging it must be possible to present helpful error messages > to the developer, but on a production system no errors from the MVC > should be shown to the user, but the developer should be able to handle > them gracefully. > > Some failures should be reported to the administrator in a technical > manner; allowing him to fix the problem or to handle the client's request > manually. > > Errors may occur during each step of the request handling, like the > following examples: > > - Router cannot parse request > > - Configured / requested controller could not be found > > - The view can't be rendered because of incompatible data or some > template parse error > > Those errors cannot be handled by the controller, because they happen > outside of it. A configurable default controller will be called for all > error messages, so the application developer may decide to send > messages, show or log the occurred error. An error during the execution > of this default controller will cause a "500 - Internal server error". > > As none of the given errors is meant to be displayed to the user of the > application (but only to the developer) no translation possibilities for > the errors need to be provided. > > TieIns for this default controller using the Execution, EventLog > and / or Mail component for error logging would be useful. > > Summary > ^^^^^^^ > > Actions should be able to cast an error specifying, at once: > > - the verbose error message, > - the non-verbose error message or id, > - the target action to bundle the error with, > - whether actors should be notified or not. > > An EventLog_ and Mail_ tie-in should be supplied by another component. > > .. _EventLog: http://ezcomponents.org/docs/tutorials/EventLog > .. _Mail: http://ezcomponents.org/docs/tutorials/Mail > > Testing > ------- > > Testing a controller is the key to quality development. Testing manually > each controller can lead to disasters: It's boring to do and therefore > humans cannot cover all controllers manually after each bug fix. The > solution is test-automation in PHP (e.g. using PHPUnit). > > Controllers run with a single argument: a request object. Controllers > return a single value: An abstract result object. Running a controller with > an request-object fixture and asserting that the result matches an > result-object fixture is the procedure to test a controller. Very good. I like this. > Summary > ^^^^^^^ > > Requested process to test a controller: > > - Create a request-fixture (which can have protocol dependent values) > - Create a result-fixture (abstract output object) > - Run the controller against the request-fixture > - Assert that the controller's result equals the result-fixture > > Conventions > ----------- > > Convention is the key for this component. Even though tie-ins will be > supplied to allow the usage of other eZ Components, all layers should be > adjustable and replaceable by the user. > > The only classes that should be common to every project are the request > object, and the request and the result abstractions. All other classes > should be defined through interfaces and only very basic implementations > will be shipped with the component. Advanced implementations can be added > at a later stage, be provided via tie-ins or can be implemented by the user > himself or be installed through 3rd party code. > > Special Considerations > ====================== > > HTTP-GET should not be allowed to invoke changes on the model because this > would cause a violation of HTTP standards. It's quite common to do though. Are you sure you want to "prohibit" this? How will you enforce it? > We should keep testing capabilities for the extensions to this component > and the applications build upon it in mind during the design and > implementation phase. > > We cannot provide the testing environment itself: > > - Does not fit into the component > - Our test "component" is not an official component and can only be used to > test eZ Components themselves. > > However, we could provide detailed information and possibly some helper > classes for the testing of applications build on this component. > > The later application configuration layer (meaning to read configuration > from config files and configuring the parts of the MVC accordingly) should > be part of a potential "Framework" component. But this should not be part > of this document nor the MvcTools component. > > In addition, this component should neither provide any automation > facilities (e.g. code generation, deployment) nor integration with > components that are not explicitly needed by it (e.g. Configuration, > Authentication or Database). Integration with such components could: Yes, very good. > - Be build using a tie-in > - Be part of a potential "Framework" component/package stuff that might be > created in future. > > Clarification of terms > ====================== > > MVC_ > Model-View-Controller (MVC) is an architectural pattern to separate data > (model) and user interface (view) concerns, so that changes to the user > interface will not affect data handling. > > Model > The domain-specific representation of the information that the > application operates on. Domain logic adds meaning to raw data (e.g., > calculating whether today is the user's birthday, or the totals, taxes, and > shipping charges for shopping cart items). The PersistentObject component > provides a persistent storage mechanism (such as a database) to store data. > MVC does not specifically mention the data access layer because it is > understood to be underneath or encapsulated by the model. > > View > Renders the action into a form suitable for interaction, typically a user > interface element. Multiple views can exist for a single model for > different purposes. The Template component provides a syntax-light > language for non-programmers to design the views. Therefore a tie-in with > the Template component should be provided. > > Controller > Processes and responds to events, typically user actions, and may invoke > changes on the model. > > Action > Controllers can provide one or several actions. Each action has a > specific process that can be called by the router. What is a process? > Router > Routers are the first layer hit by input and the last layer that > processes the output. That is why it handles routing requests to the > appropriate action and abstracts the request/response protocol. > > Fixture_ > Fixtures are objects that are set to an arbitrary state for testing > purposes. > > Abstraction_ > It is the process or result of generalization by reducing data, typically > in order to retain only information which is usable by any router for any > protocol. > > Request > The data that comes in through any protocol possible from the client to > the server. The request data consists of headers, variables, files etc and > is encapsulated in the ezcMvcRequest object. > > Result > The abstract result of a controller action that can be used by the view > manager to generate a response. > > Response > The data that is send from the server to the client that has been > generated by the view manager from the abstract result object. After reading all of this I still didn't really catch the general flow of a request. Would it be possible to make a diagram of that? How are the different parts supposed to interact. Cheers, Frederik -- Components mailing list Components@lists.ez.no http://lists.ez.no/mailman/listinfo/components