[Zope-dev] __before_publishing_traverse__ calls RESPONSE.redirect(): is there another way to change the browser URL?

Craeg K Strong cstrong@arielpartners.com
Fri, 27 Sep 2002 23:17:19 -0400


Casey Duncan wrote:
 > What you are looking for sounds like "stateful" through-the-web functionality.
 >
 > I think you should use sessions to remember the form fields and/or whether the
 > user has been to this URL before.
 >
 > I am suspect of an app design that makes a single URL mean different things in
 > this way, however. I suspect there is a much easier way to accomplish what
 > you want that does not use traversal hooks or magic redirect descrimination.
 >
 > I'm still not sure I'm seeing the big picture of what you are really trying to
 > accomplish here.
 >
 > -Casey

Hmm  You are probably right.  I confess I have not looked into the
SessionDataManager stuff yet, but it looks like now would be a good
time :-)    I will look into it and report back..

For those who are interested, the following is a bit of elaboration on our
application architecture, which will explain why my question came up in
the first place.  For those who are not, feel free to hit the delete button
now :)

Our application is a typical forms-based business app.  Each page is a ZPT
with one or more forms on it.  Each business transaction is encapsulated by
a Command (a la GOF Command pattern).  That gives us "undo", logging, etc.
for every command in a uniform way and separates business logic from GUI
logic.

Every business object is published at a unique URL.  That is, a contract with
ID "123" would be published at myapp/contracts/123.  We use a mnemonic naming
scheme:

myapp/contracts/123  --> GET:  get a human readable HTML read-only 
representation of the resource

myapp/contracts/123/xml --> GET: get an XML representation of the resource

myapp/contracts/123/edit --> GET: get a human readable HTML form for modifying 
the resource

myapp/contracts/123/xml --> POST: replace the current state of the resource with
the state indicated by the passed-in XML document

This makes our app equally usable by humans and other apps, and also makes
beautiful reports easy to build using XSLT against the xml representations.

*However* we don't want to embed *any* URLs in our ZPT code.  All the forms
in the ZPT look like the following:

<form action="." method="post">
   <input type="hidden" name="stateName" value="Home"/>
   <input type="hidden" name="actionName" value="EditInvoice"/>
   <input type="hidden" name="contractId" tal:attributes="value python:contract.Id"/
   <input type="submit" name="step:method" value="Edit Invoice"/>
</form>

There is a one-to-one relationship between ZPTs and application states.
If you are in the "EditingInvoice" state, you are looking at the
EditingInvoiceForm.zpt

Similarly, Commands are pure-python beings.  They are not allowed to know
URLs.  The application defines a number of states and actions in a finite
state machine.  The step() method asks the finite state machine for the next 
state given the current state and the command ("actionName" above).
The application then actually executes the
appropriate command, and finally executes
its own internal algorithm to determine the proper URL to go
to given the resulting state.

For example, it knows that if the state is "EditingContract" then
there must be a "contractId" in the REQUEST, and the resulting
url is "contracts/" + contractId

Since our business objects (like contracts and invoices) are pure-python
(i.e. non-Zope objects), we do all of the traversal machinery in
the __before_publishing_traverse__ and __bobo_traverse__ hooks.

Some might say we pay a high price for purity :-) but it pays
dividends in the robustness and ease of maintainability of the code.
In many ways, we are trying to simulate a Zope-3 app on top of Zope2.5.1

Once again, thanks for all the help!

--Craeg


> 
> On Friday 27 September 2002 02:53 pm, Craeg K Strong wrote:
> 
>>Hello:
>>
>>This is a good idea, and would solve the problem as stated.
>>
>>Unfortunately, it conflicts with my other (heretofore unstated)
>>requirement that
>>
>>"all URLs shown in the browser should be bookmarkable
>>at all times."
>>
>>Once a user bookmarks foo?I_am_an_application_controlled_redirect=1
>>and comes back to it, it is no longer telling the truth ;-)
>>
>>--Craeg
>>
>>Oliver Bleutgen wrote:
>>
>>>Craeg K Strong wrote:
>>>
>>>
>>>>However, I would like to distinguish between two cases:
>>>>
>>>>a) Direct Navigation:   e.g.I am a user and I just typed in
>>>>
>>>>
>>>
> http://acme.com/myapp/contracts/TRW-001/taskorders/TO-01/invoices/DSDC-001-9301 
> 
>>>>
>>>>into my browser
>>>>
>>>>b) Application-Controlled:   e.g. I am the application, I did some 
>>>>processing
>>>>based on a button the user pressed in some form somewhere and determined
>>>>that the next URL should be
>>>>
>>>>
>>>
> http://acme.com/myapp/contracts/TRW-001/taskorders/TO-01/invoices/DSDC-001-9301 
> 
>>>>
>>>>====Now here is the issue====
>>>>
>>>>In both cases above, the REQUEST object looks identical.   Is there 
>>>>any way
>>>>that I can distinguish a GET that is the result of a REDIRECT from one 
>>>>that
>>>>is not?
>>>>
>>>>I would think this would be of interest to others.  For example, if I 
>>>>move my
>>>>web page and put a redirect from the old address, I could track how many
>>>>people came to my web page directly versus those that are still using the
>>>>old address and are getting redirected.
>>>
>>>
>>>raise 'Redirect', newURL+'?I_am_an_application_controlled_redirect=1'
>>>
>>>
>>>HTH,
>>>oliver