"""Document the API for screen classes.
Screens are the focal point of interaction with the user. In general, the URL
controls which screen is shown. There are two types of screens: controllers
and views. Controllers contain business logic and are written in Python.
Views contain display logic and are written in Cheetah.
Controllers
===========
Controllers are responsible for:
Making changes in state:
For example, using a database module to insert a new row into the database is
a change in state.
Conveying the results of the user's actions:
For example, "The item has been added to your shopping cart." or "Your credit
card is invalid." In general, controllers whose main purpose is a change in
state (e.g. add_item) *should* set ``actionResults``
(``self._ctx.actionResults``) to the appropriate message. See the
aquarium.layout.LayoutAPI_ for more details. Controllers whose main purpose
is to prepare data to be shown on a view (e.g. ``show_messages``) should
*not* set ``actionResults``. This is not a rule, it's just an observation.
You may choose to store ``actionResults`` in the session instead of ``ctx``
if you want it to survive redirects.
Preparing the data to be shown on a view:
Views are usually written in Cheetah, so as much work as possible is pushed
into the controller where doing a lot of complex Python is more convenient.
If a controller passes a single argument which is an instance of some class,
that instance is called "the bean" (in fact, aquarium.layout.Bare_ will even
save it as ``self.bean`` for your convenience). Since controllers must often
do double duty (they change state as well as prepare for the view), the
aquarium.screen.Controller_ superclass has a method named
aquarium.screen.Controller.executeAction_ that can isolate state changing
code in methods of the form ``doFooAction``.
Choosing a screen to show:
Depending on the form parameters given to the controller, it may choose which
screen to show next. This screen may be either a controller or a view. If a
controller's main task is to prepare some data to be shown on some view, the
controller will be named something like ``foo.py`` while the view will be
named something like ``foo_view.tmpl``. Note that I use lower case names
because that is most common in URLs.
Forwarding processing to a screen:
Once the next screen to show is chosen, the controller directs processing to
that screen via ``self._ctx.iLib.forward(screenModule, args...)``. Please
note that this method does *not* return. Please see the documentation for
aquarium.util.InternalLibrary.forward_ for more details.
As a last note, controllers are free to subclass any other subclass of
aquarium.util.AquariumClass_ they want. However, it is common to first create
a subclass of aquarium.screen.Controller_ and then make all of your controllers
subclass that class.
Views
=====
Views are responsible for displaying content. Views encapsulate the main
content returned as a result of some request. Views subclass layout classes.
For instance, if the main content of a Web site is always in the middle, with
navigation buttons along the top, each view in the Web site would subclass a
layout named ``TopNav``. Sometimes views are used to generate non-HTML
content, such as an XML report. In such cases, it is customary to subclass the
layout aquarium.layout.Bare_.
Views that have a ``__call__`` method that receives arguments (other than
``self``) are not directly accessible from the outside. Trying to use a Web
browser to request such a view directly will result in an exception. (When the
layout tries to call the view's ``__call__`` method without any arguments, a
``TypeError`` exception will occur.) This type checking is by design. Having
Python enforce the API between the controller and the next screen is a real
strength of Aquarium in contrast to JSP style forwards.
Other Details
=============
The astute reader may wonder, "If I have view and controller, where is the
model?" Aquarium enforces the use of controllers and views, but the
distinction between controller and model is entirely up to the
developer/application. You can make the controllers as "thin" or "heavy" as
you wish.
Controllers and views are stored in the same directory because experience shows
that if you're working on one, you'll probably want to work on the other. The
modus operandi is to have a directory hierarchy that matches the hierarchy
found in the URLs for the Web site. Within each directory views and
controllers sit side by side.
Controllers and views have the same API in that both must implement a
``__call__`` method:
__call__
Return the contents of this screen as a string or do a forward.
To support streaming very large or infinite amounts of data, instead of
returning a string, ``__call__`` may be a generator or return a generator.
Note, however, that you can't easily do this in Cheetah because every Cheetah
method implicitly does a return. See the echo_ screen for an easy way to use
this feature.
.. _aquarium.layout.LayoutAPI: aquarium.layout.LayoutAPI-module.html
.. _aquarium.layout.Bare: aquarium.layout.Bare.Bare-class.html
.. _aquarium.screen.Controller: aquarium.screen.Controller.Controller-class.html
.. _aquarium.screen.Controller.executeAction:
aquarium.screen.Controller.Controller-class.html#executeAction
.. _aquarium.util.InternalLibrary.forward:
aquarium.util.InternalLibrary.InternalLibrary-class.html#forward
.. _aquarium.util.AquariumClass:
aquarium.util.AquariumClass.AquariumClass-class.html
.. _aquarium.screen.echo: aquarium.screen.echo.echo-class.html
"""
__docformat__ = "restructuredtext"
# Created: Mon Mar 29 14:09:24 PST 2004
# Author: Shannon -jj Behrens
# Email: jjinux@users.sourceforge.net
#
# Copyright (c) Shannon -jj Behrens. All rights reserved.
|