[Zope3-dev] should the view lookup machinery call getAdapter?

Casey Duncan casey@zope.com
Mon, 01 Apr 2002 14:17:47 -0700


Ok, first let me just say that this change was intended only as a quick 
fix to get the CVS back into a working state.

I am now working on a security reorg branch that changes a few things. 
For one thing, IAttributeMomentoStorable is too specific. The view 
shouldn't care how the momento is stored. I have added an interface to 
my branch called IMementoStorable which IAttributeMomentoStorable now 
derives from. Things that need to use momentos can simply reference 
IMomentoStorable and let the application figure out how to actually 
store it (attributes would be the default in most cases).

I am bothered by the fact that this view needs to know something (or 
declare something about momentos), since momentos are not really part of 
the security system at all, but I think I can live with it so long as 
the importance of momentos is clear in the docs.

Steve Alexander wrote:
> R. David Murray wrote:
> 
>> This may all be a result of my misunderstanding how things
>> currently work, but:
>>
>> I noticed on the checkins list that Casey did the following:
>>
>>
>>> <browser:view name="RolePermissionsManagement"
>>>              for="Zope.App.OFS.Memento.IAttributeMementoStorable."
>>>              factory="Zope.App.Security.RolePermissionView." />
>>
>>
>>
>> It seems to me that the goal would be that this view would work for
>> any object that supports the IMementoBag interface.

No, IMomentoBag is the interface for the storage container itself (a 
mapping interface), not the object the momentos are stored in. I created 
the IMementoStorable (marker) interface for this use in declarations (it 
would not be directly implemented, only derivations would be). This is 
the interface that a declaration would use to say: "for something that 
stores momentos".

[snip]
> Let's think about what you have, and where you want to get to.
> 
> We have a content object. We want to know if we can get it to store 
> Role-Permissions information for us.
> 
> The IAttributeMementoStorable interface is a contract between a content 
> object, and anything else, that says "you can use my __memobag__ 
> attribute". The content object give others permission to use one of its 
> attributes, and promises not to mess with that particular attribute.
> 
> A declaration, as above, can be interpreted as providing a quanta of 
> declarative knowledge. It is saying something that shall be true; an 
> affordance; a thing that may happen in the system.
> 
> So this particular declaration is saying "If you've got a content object 
> that implements IAttributeMementoStorable, you can see its 
> RolePermissionManagement view".
> 
> 
> As IAttributeMementoStorable is only one particular way of associating 
> an IMementoBag with a content object, we'll need other declarations for 
> the other FooMementoStorable interfaces.

This is not true in the case of this view since it does not care how the 
momentos are stored. It does a getAdapter on IMomentoBag which is 
storage agnostic.

> So, that's fine when we look at it from the point of view of the content 
> object
> 
> The problem with this is that whenever we create a new 
> FooMementoStorable, we'll have to add declarations for all of the 
> different views that work with IMementoBags.

Hopefully my general IMomentoStorable interface alleviates that.

> This might be ok if there are only ever a couple of MementoStorable 
> schemes. However, there is also the problem that when you add other 
> views that work with IMementoBags, you'd have to add declarations for 
> each of the MementoStorable schemes.

That would be unworkable.

> So, ideally, we want to say in one place how content objects can be 
> associated with IMementoBags, and in another place what things can work 
> with IMementoBags.

Yes, that level of abstraction would be desirable.

> One way of solving this is, as RDM said, to declare that the 
> RolePermissionsManagement view works with anything, and dynamically 
> check adapters in the factory registered in the directive.

This was one solution I also thought of (which is actually currently 
implemented in my sandbox), but it does not work entirely right.

> This is not a good solution, as RDM pointed out, because it adds a 
> procesing overhead, and also because the whole thing has become less 
> discoverable. That is, we've lost the explicit declaration that 
> RolePermissionsManagement needs an IMementoBag.

Try this on for size:

<browser:view name="RolePermissionsManagement"
               for="Zope.App.OFS.Memento.IMementoStorable."
               factory="Zope.App.Security.RolePermissionView." />

> My solution:
> 
> A better way of solving this is to expand the view registry so that it 
> can register transitive relationships between adapters.
> Consider these declarations:
> 
>   What you have                    What you can get
> 
>   IAttributeMementoStorable        IMementoBag
>   IMementoBag                      RolePermissionsManagement view
> 
> In the zcml files, you'd declare that an adapter exists for adapting 
> IAttributeMementoStorables into IMementoBags. We also say that the 
> RolePermissionsManagement view needs an IMementoBag.
> 
> We add an attribute transitive="yes" to the 
> IAttributeMementoStorable->IMementoBag declaration.

What I have done is say:

RolePermissionsManagement requires IMementoStorable

When object foo walks up and says "view my RolePermissions", then it 
must implement some derivation of IMementoStorable, such as 
IAttributeMementoStorable. Unless it defines its own storage scheme and 
declares it itself.

> We need to change the component registries to have a two-phase 
> initialisation. Inside the component registries, any adapters that get 
> registered with transitive="yes" are registered as usual, and also added 
> to a list for processing in the second phase.
> 
[snip]
> 
> Then again, we might find that if we transitively register all adapters, 
> that most of the second-phase work is a no-operation, and by default all 
> adapters can be registered transitively.

I think I can agree that this might have a use. However, what about just 
using the interface inheritance as above to perform the abstraction for you?

I think we need a few concrete use cases that cannot be solved using 
inheritance.

-Casey