Re: What does Five and Z3 mean for Archetypes?
whit <whit-UE+B0n23d/[email protected]>
| Newsgroups | gmane.comp.web.zope.plone.archetypes.devel |
|---|---|
| Message-ID | <[email protected]> |
utilities are like a tool in the cmf, but currently can be either global
or local. This is a solution for the kind of problem posed by
PortalTransforms and MimeTypesRegistry, where localization by site
rarely serves much purpose except creating a needless duplication.
<snip>
> Okay. So when I see things like:
>
> class IMyContent(Interface):
> myTitle = TextLine(title='Enter a title')
>
> ... that looks like an AT schema to me. What's the difference?
>
at the level of fact orientation ie "I want to make a form", not much.
But the devil is in the details. As a pattern, z3 schemas are an
interface that an object can be adapted to (resulting in a form).
Archetypes schema are a data structure composes of multiple different
object types that define all the getters and setters for data, configure
it's display, and even determine such things as metadata and relations.
Purist will point at at and say "impure MCV". this is true, but the
convenience and power of resulting from an AT schema is a primary reason
for it's popularity. A z3 schema just gives you a form, but have to go
flesh out much of the behavior elsewhere.
>
>>AT schemas are actually micro-content, an bundle of smaller object.
>>
>>Looking at this from a z3 standpoint, widgets are views on field
>>objects. It would be trivial and cool to write a widget that actually
>>rendered a multi input zope3 schema for a single field. you get the idea.
>
>
> What do you mean by multi-input zope3 schema?
>
> Could we fix the incredible broken-ness of Fields/Widgets with Five views? How
> might that look?
I think we could. Part of the issue here is somewhat below the issue of
mixing model and view. I think it may be more of an issue of mixing
configuration and behavior. If we view the AT schema as a way to
configure the behavior on an otherwhise generic CMF type (ie folder or
content, nothing else), then we are no longer so married to the
decisions made there.
much of the pain is from the persistent duplication of site wide
configuration (ie the widget, storage, marshall and every property set
in a field or widget) on an object by object basis. Using adapters and
views, we can abstract this configuration out of the object, leaving the
schema to be a generic bag of objects, devoid of any restricting logic
of how they should act.
>>2. AT is an different, and complementary framework to z3.
>>
>>Much of what AT attempt to do (good, bad, or etc) can be made better
>>using adapters to replace inheritance and other disunified
>>mini-component architectures within AT. Events will let us defer AT's
>>ugly indexing dance to the end of a transaction. Adapter will let us
>>break AT into interchangeable pieces.
>
>
> Yes!
>
> And how do we get about getting there? Is it feasible to do some of this in
> stages (i.e. get an events system, then fix widgets, etc.)? Is there any process
> or anyone looking at this now?
I think the nicest part about component architecture is that this can
happen in stages. One place to look is at how Five has gone about
changing Zope 2.
Following this model, we can do some structured monkeypatching of AT to
prototype where and how we want to decompose the structure, and as we
find things that work and are tried and true, move them into ATs core.
also, similar to Five and Z3, is that ben has done a bunch of
prototyping for AT2 with an events based core. and according to the
outcome of conversations between jim and ben, the events core will work
with z3 and five.
Having clean developed code to integrate back into the thorny messy of
legacy often is easier than keeping clean in the briar patch. this is
about the only good justification I can think of for rewriting from scratch.
the key is creating the right indirections to make backward
compatibility easy and optional, rather than an albatross that drives
ben away to write AT3.
> <snip code>
>
>>Pretty unimpressive. But since you can configure what class is use for
>>the factory, the schema can from just about anywhere and all that has to
>>change is the zcml. This has some pretty big implication, one being that
>>schemas don't need to live inside objects.
>
>
> Right. So you've made an adapter (GetSchema) to get the schema from the object,
> but other adapters could e.g. get a dynamic schema defined in the GUI and stored
> in an RDBMS ... or something. Correct?
> Could you then use ZCML in a custom AT product to define a different adapter
> (GetSchemaFromVisualEditor) just for that type?
>
bingo!
>>this sort of requirement to pass in both the field and and instance
>>becomes a pain whenever you try to reuse widgets and/or fields outside
>>of AT. but, if field only held data and/or policy, this wouldn't be an
>>issue. A named adapter might fit the bill here, then a view for the
>>widget (registered the same as above).
>
>
> That's very cool. Being able to re-use widgets would be a big step forward.
> Could you show an example of how such re-use may take place?
the widget is just a view, so any object that the view is registered for
could use the widget. the modality would be moved into
configuration; a "widget" would actually be a bundle of views (search,
edit, view, etc). Configuration might look something like this (this is
a though excercise and this actually might really suck, so don't hold me
to implementing it):
<!-- widgets
<at:define_widget
for="ILinesField"
name = "TagWidget"
search="IKeywords"
edit="ILinesTextArea"
view="IDisplayText"
/>
<at:define_widget
for="ILinesField"
name="IChooseOne"
search="IKeywords"
edit="ISelect"
view="IDisplayText"
/>
so, to make this pseudo directive work, you would need an adapter that
dealt with form processing the data type stored ie ILinesField(field).
Then, each mode interface would be a view on that adapter(the adapter
handles the duties of process_form, getting and setting, etc).
The cool thing is that both of these "widgets" could then work on the
same field, but be registerd to interfaces that returned the appropriate
view based on aspect (ie the situation, perhaps determined by permission
or other metadata) rather than simply the object type.
As you can see, the sub components represent modes get reused.
hypothetically you could use the widget bundle or any of its components
on anything fufilling the ILineField contract.
These could be extended to handle offer other types of view modalities
say for offering web services.
>>from zope.app import zapi
>>from zope.component import getView
>>contacts_field = zapi.getAdapter(myAT, ILinesField, 'contacts')
>>
>>value = contacts.get()
>>view = getView(contacts, 'edit', request)
>
>
> This one's a little abstract for me. What does getAdapter() do in this case wrt.
> to the 'contacts' field? I assume it gets the ILinesField implementation for the
> 'contacts' field in the schema, but how does this generic Zope function know
> where to get it from? (I assume there's some ZCML somewhere...)
>
> What is the view used for in this case? What is the 'edit' parameter used for?
very good questions...and reminds me of what it looked like before it
made any sense.
getAdapter is a lookup that finds a factory that matches the triple of
the object's interface, the interface passed in and, optionally, a name.
then is instanciates the adapter and returns it(or, you can actually
bastardize the system to return just raw data, but Jim1 doesn't think
that's kosher...yet)
the view is just an object that can be published to html. calling view()
might spit out <p>Contacts: <input name="contacts" value="5"></p> or
whatever.
"edit" is the string you would see in the URI (lets pretend schema were
traversable): /portal/myAT/contacts/edit .
>
>>again, nothing spectacular, but when you consider that what view is
>>returned can be configured outside changing the code of the archetype,
>>the field, or the widget, and done on a field by field, mode by mode basis.
>>
>>Those are just a couple example of where things may be going. Coming
>>back from vaporware, I would suggest this: any problem that you
>>consider creating a mixin to share some general behavior between types,
>>create interfaces for the types, and then write an adapter instead.
>
>
> Yes, I'm starting to get that feeling. :)
>
>
>>For existing types, five provides an "implements" directive which allow
>>you to add interfaces to existing classes without having to edit the
>>code. The "bridge" directive allow you to bridge existing z2 ifaces to
>>z3 ones. then, just create an interface for your behavior, deploy it at
>>the appropriate junction and adapt.
>
>
> Okay, can you show how this would be used in a real use case?
>
A good example indexing, where you have multiple types that need to be
searched horizontal across type by the same index. I'm going to address
your following question because they are related
>
>>One of the first things I noticed was the need for methods inside
>>classes in AT goes away. This cleans up code quite a bit, and testing
>>is much easier. and, it's easier to reuse code.
>
>
> How is this? Where do you now store your type-specific logic? How do you invoke
> this logic in code outside your type?
because the logic lives in the adapter not the type. To have that logic
shared, I simple register multiple types to the Interface the adapter is
providing for, and now those types can also provide said logic.
For example...
In the rosetta project, I used AT objects to represent language trees,
using a simple hierarchy of child->parent relationships. I defined a
type to represent the tree and another to represent the nodes within the
tree.
The tree served as a container for all the nodes in a family (let's term
this the physical relationship) and also maintained a network of
references that tracked the child->parent relations of all the members
(the aspect relationship).
The tree also served as the head node, and therefore had to be treated
like a node in any computation of the hierarchy. The second layer of
indirect with references was required because linguist might introduce
other taxonomic trees using child parent relationships that were not
containers used for the maintenance of the site.
On top of this, I needed to generate javascript trees based on the
taxonomic structure including all nodes and the tree as the head node.
To solve this mess, I generated path expressions base on the
relationships of the nodes. This allowed me to query a catalog, return
the relationships and generate a tree for the particular tree or node
object (oh yeah, these trees were displayed node by node as a
navigational feature)
Sorry for all the back story....here is the real world application:
1. Nodes, FamilyTrees and GenericTrees all need to generate a path based
on where they are in their tree for indexing.
Solution: INodePath
IClassificationTree (for FamilyTree and GenericTree)
INode (for nodes)
register adapters for IClassificationTree, GenericTree and INode so
nodes and trees can provide INodePath for the catalog (using
ExtensibleIndexableObjectWrapper)
2. Trees and nodes need to display a navtree based on family membership,
but that tree has different rendering requirement depending on whether
it's a tree or a node.
same pattern, except this time with a view (zmori in the collective is
the result of this)
one view: ITreeView (registered INodePath)
ITreeData (used by view to get data from context)
For this, I registered three seperate adapters, since family trees are
actually rooted in "All Families of Languages", generic trees are not
connected to anything but the person who created them, and Nodes need to
have the tree render open to the current context.
>
> Right. So I use this field in my AT schema, I say, I expect the instance to
> comply to interface X (dottedname), and in that interface, I want the field to
> return the value returned by Y (callmethod). Correct?
close... the dottename is the interface the at object is adapted to
rather than one the object already provides. perhaps a more descriptive
property is in order like "adaptTo"
Of course, if your object directly provides this interface, the result
is just a indirected ComputedField. Again, when apples and oranges just
need to be fruit, this works pretty well too ;)
> Thanks a lot, Whit!
>
> Sorry for asking a lot of stupid questions, but I prefer asking too much rather
> than making my own assumptions and discovering they were wrong. :)
no problem!
thinking stupid(lazy, impatient, and stupid) is the only way to go.
there were a bunch of stupid questions I wished I had ask before going
onto z3 base to ask why my first adapter was failing at transforming
ATImage objects into ATLink objects (I was pretty stoked on my magic
workflow idea). I owe most of what I know to the guys on z3-base and
the fact that Five itself is a pretty good read.
z3 can be really quite alien to the zope/plone hacker at first (less so
if you have worked with other python frameworks). Aside from annoying
failures with asymtomatic errors (ie why is the entire component
architecture not loading or why does my view not show up and not give
any error), it is deceptively easier.
there are a few things missing that you might expect(transitive
adaptation ie PyProtocols, a simple way to return data without getting
an adapter), but all in all it's a breath of fresh air.
-w
-------------------------------------------------------
SF.Net email is sponsored by:
Tame your development challenges with Apache's Geronimo App Server. Download
it for free - -and be entered to win a 42" plasma tv or your very own
Sony(tm)PSP. Click here to play: http://sourceforge.net/geronimo.php