Mikko Ohtamaa <[email protected]> writes:

> Brandon, I like your enthusiasm towards Plone :)

Thanks. :-)

> My rationale ...
> * Web best practices say that friendly URLs are must.
> * @@ does not look friendly in URL.
> * /getpaid-checkout does not look as friendly as /checkout in URL

You're right, "getpaid" does look pretty ugly in a URL.

You've convinced me!  Let's go with new, simple URLs like "/checkout".
I'd still love to give shop owners the *option* to move our views "one
level down" in their Plone site, beneath a URL of their own choosing
like "/shop" or whatever, which would also prepare us for web frameworks
like Turbogears and Django that want products to live beneath their own
URL prefix.

How would this work, technically?

Currently, our code does something like this to figure out where the
checkout wizard lives:

    portal = getToolByName( self.context, 'portal_url').getPortalObject()
    url = portal.absolute_url() + '/@@getpaid-checkout-wizard'

Now, this tells us right off the bat that, as I observed yesterday, the
registration for this view is overly broad:

  <browser:page
     for="*"
     name="getpaid-checkout-wizard"
     class=".checkout.CheckoutWizard"
     permission="zope2.View"
     />

Since, as the above code demonstrates, we always expect the checkout
wizard to live right beneath the Plone site's main URL, there's no
reason not to tighten the view registration up and say this instead:

     for="IStore"

so that every other object in the Plone site doesn't gain a
"@@getpaid-checkout-wizard" view that it doesn't need.

How could we change the assumption built into the above code - that our
views always live on the portal root - so that we also have the option
of living beneath another URL instead?  I can think of three ways:

 1. We currently slap an "IStore" marker interface on the Plone portal
    itself.  If we treated it instead as a utility that was merely
    registered with the current portal, then it could live anywhere
    instead.  To find the store, you just ask for the "IStore" utility.
    If the site owner is using the default setting, then the portal
    itself will have had the "IStore" marker placed on it, and the
    checkout page will live at "/Plone/checkout".  If the site owner
    instead said to put everything under "/shop", then a simple "shop"
    object will have been created inside the Plone site and *it* will
    have been registered as the "IStore" utility.  Under other web
    frameworks, we would just jury-rig a global utility registration
    pointing at an IStore object that knows where in the Django or
    Turbogears URL tree GetPaid has been installed.

 2. But maybe it would be a Bad Thing to move the "IStore" marker off of
    the portal, since that would both move all of our configuration
    views down on to the "/shop" URL instead, if the site owner asked
    for one?  On the one hand, having the configuration URLs move around
    might be not just nice, but necessary, if we think that a TurboGears
    integration of GetPaid would re-use our configuration screens, since
    they can't there live at the site root very comfortably.  But, in
    Plone, it seems plain awkward for site-configuration views to live
    anywhere else but on the Plone object itself.  Plus, a quick search
    of the source code suggests that "IStore" is used two ways that are
    incompatible with moving it away from the portal root: it's used as
    the name for the Store's adapter-and-interface registry where
    various GetPaid products register themselves, and the installation
    of the IStore marker interface is used as an event trigger by at
    least some of the shipping code.  So, if all of the above reasons
    are good ones for leaving "IStore" alone and keeping it as the name
    of the portal root and Zope 3 registration point, then we would want
    to create another utility name - maybe "IStoreContext"? - that
    serves as the base URL off of which our checkout views live.  There
    would be three situations:

    a. In a default Plone install, the portal root would be both an
       IStore and an IStoreContext, making it both where you go to see
       configuration views, and also where you go to find the cart and
       checkout views.

    b. In a Plone install where the owner asks us to live beneath
       "/shop", their portal root remains an IStore, and so all of their
       Site Setup views would continue to live at places like
       "/Plone/@@manage-getpaid-content-types" (note that we allow
       ourselves here both the "@@" eyes looking at us and also the name
       "getpaid" in the view name, since this URL will be seen, if at
       all, only by site admins that expect that sort of thing), but the
       "/Plone/shop" object we create is both marked as an IStoreContext
       and also registered as the site's IStoreContext utility.  That
       way, URLs that say "/Plone/shop/checkout" would traverse to the
       IStoreContext and find the "checkout" view waiting beneath it,
       and checkout code that needs to generate URLs would just ask for
       the IStoreContext utility, then ask it for its URL, then slap
       "/cart" or whatever on their end.

    c. In a non-Zope framework, "/shop" would be configured using the
       host's URL registration framework as pointing at a special object
       that is itself marked as both an IStore and an IStoreContext, and
       that launches Zope traversal when a URL lands on it.  Any config
       views that survive in the other framework, as well as all of our
       customer-facing views, would live under "/shop" in the web site.
       We would create a global registry at start-up that advertises our
       "shop" object as both the registered IStore utility and
       IStoreContext utility.

 3. We abandon the modern idea of utility registration for the older
    idea we're currently using of merely being able to find our global
    options and ask it questions.  Recall that at the moment we find
    things out about the current payment processor, when that knowledge
    is needed, with code like this:

        portal = self.context.portal_url.getPortalObject()
        manage_options = IGetPaidManagementOptions( portal )
        processor_name = manage_options.payment_processor

    In other words, instead of asking for a utility, we ask for the
    portal root and then forcefully adapt it to the Options interface;
    that is, we pretty much insist, through the way we write our code,
    that configuration be stored on the site root itself, *not*
    somewhere else.  I would argue against using such code, since, if
    we're not in Plone, (a) there might not exist a site root, and (b)
    even if there were, it might not be the best place to put our
    configuration information.  I like the idea of an IStore utility
    that configures us and an IStoreContext utility where our views live
    because they are so abstract: they don't insist that we're part of a
    Plone site at all, they just require that whatever kind of web
    framework we're in be supplied with the ability to provide us with
    both of these utilities.

    Anyway, as I was saying: if we don't want to use utilities, we could
    hang everything off of the ability to get at the global options
    object (and, in other web frameworks, somehow fake things so that
    something that looked like a portal could be found through something
    like the above code).  So instead of asking for where the current
    IStoreContext is, we could just grab the global options, and ask
    them what URL our checkout views should live beneath; and the global
    options would have that information because it's through changing
    the global options that the store owner expresses their will.

Okay, enough options for right now. :-)

Now, it might be that I'm creating an artificial distinction here
between the "pretty" option of having an IStore and an IStoreContext
utility, and the "ugly" option of grabbing the portal root and making it
adapt to IGetPaidManagementOptions, because there is a third way between
these two extremes: we could register the options themselves as a
utility, and demand that utility as the first act we perform when we
need to learn where GetPaid lives or where it is wired up.

I admit, as I noted in an earlier email, that the idea of starting
*every* question about GetPaid with "go get the options" is very pretty,
because, that way, everything GetPaid needs to know is stored one place.
With my suggestion above that we store *two* different utilities in
every Plone site that uses GetPaid, we start the process of scattering
our configuration information far and wide, where lots of things
(site-wide registrations, for example) have to be changed or cleaned up
when GetPaid is reconfigured or uninstalled.

So, maybe the way to go it to turn the Options into a utility, so that
we can get to it without needing a portal-root to exist, and give *it*
an option that knows where in the site GetPaid is supposed to exist?
Hmm.  That wouldn't completely solve the problem, though, since for the
URL "/Plone/shop/checkout" to resolve, there's *got* to be a "shop"
object that actually, really exists in the site.  So I'm not sure we can
get away without having *some* site-wide registrations or object
creations going on, unless we give up the idea of Plone users being able
to put our URLs beneath some sub-URL.

And maybe that's an idea we should give up for now, and just try to nail
the two more "obvious" use-cases of Plone with our views living right
beneath the root, and of other web frameworks having us live beneath a
sub-URL, and in both cases we just ask for our Options and find out from
them how to compute our URL?

Hmm.

I should think about this more.

One last option: I think it is *possible*, last I checked, to have views
that (gulp!) live inside of other views.  So instead of creating an
actual "shop" *object* in the "/Plone" container of a site owner that
wanted our URLs to live under "/Plone/shop", which would then need to be
cleaned up or deleted later (and which the shop owner would see in their
table of contents and might delete by hand if they didn't know how it
had gotten there), we could register a named view on "IStore" named
"shop" that, itself, has views like "checkout" and "cart" registered for
it.  I think that the "vice" RSS syndication system did something like
that to construct interesting multi-part URLs beneath Plone folders
(like ".../recent/rss" and ".../all/atom"), but I'd have to go read
their code to remember how they worked.

-- 
Brandon Craig Rhodes   [email protected]   http://rhodesmill.org/brandon

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"getpaid-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/getpaid-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to