diff -r 76ab3c71aff2 -r c67bcee93248 doc/book/en/devrepo/entityclasses/adapters.rst --- a/doc/book/en/devrepo/entityclasses/adapters.rst Mon Jul 06 17:39:35 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,167 +0,0 @@ -.. _adapters: - -Interfaces and Adapters ------------------------ - -Interfaces are the same thing as object-oriented programming `interfaces`_. -Adapter refers to a well-known `adapter`_ design pattern that helps separating -concerns in object oriented applications. - -.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html -.. _`adapter`: http://en.wikipedia.org/wiki/Adapter_pattern - -In |cubicweb| adapters provide logical functionalities to entity types. - -Definition of an adapter is quite trivial. An excerpt from cubicweb -itself (found in :mod:`cubicweb.entities.adapters`): - -.. sourcecode:: python - - - class ITreeAdapter(EntityAdapter): - """This adapter has to be overriden to be configured using the - tree_relation, child_role and parent_role class attributes to - benefit from this default implementation - """ - __regid__ = 'ITree' - - child_role = 'subject' - parent_role = 'object' - - def children_rql(self): - """returns RQL to get children """ - return self.entity.cw_related_rql(self.tree_relation, self.parent_role) - -The adapter object has ``self.entity`` attribute which represents the -entity being adapted. - -.. Note:: - - Adapters came with the notion of service identified by the registry identifier - of an adapters, hence dropping the need for explicit interface and the - :class:`cubicweb.predicates.implements` selector. You should instead use - :class:`cubicweb.predicates.is_instance` when you want to select on an entity - type, or :class:`cubicweb.predicates.adaptable` when you want to select on a - service. - - -Specializing and binding an adapter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. sourcecode:: python - - from cubicweb.entities.adapters import ITreeAdapter - - class MyEntityITreeAdapter(ITreeAdapter): - __select__ = is_instance('MyEntity') - tree_relation = 'filed_under' - -The ITreeAdapter here provides a default implementation. The -tree_relation class attribute is actually used by this implementation -to help implement correct behaviour. - -Here we provide a specific implementation which will be bound for -``MyEntity`` entity type (the `adaptee`). - - -.. _interfaces_to_adapters: - -Converting code from Interfaces/Mixins to Adapters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Here we go with a small example. Before: - -.. sourcecode:: python - - from cubicweb.predicates import implements - from cubicweb.interfaces import ITree - from cubicweb.mixins import ITreeMixIn - - class MyEntity(ITreeMixIn, AnyEntity): - __implements__ = AnyEntity.__implements__ + (ITree,) - - - class ITreeView(EntityView): - __select__ = implements('ITree') - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - children = entity.children() - -After: - -.. sourcecode:: python - - from cubicweb.predicates import adaptable, is_instance - from cubicweb.entities.adapters import ITreeAdapter - - class MyEntityITreeAdapter(ITreeAdapter): - __select__ = is_instance('MyEntity') - - class ITreeView(EntityView): - __select__ = adaptable('ITree') - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - itree = entity.cw_adapt_to('ITree') - children = itree.children() - -As we can see, the interface/mixin duality disappears and the entity -class itself is completely freed from these concerns. When you want -to use the ITree interface of an entity, call its `cw_adapt_to` method -to get an adapter for this interface, then access to members of the -interface on the adapter - -Let's look at an example where we defined everything ourselves. We -start from: - -.. sourcecode:: python - - class IFoo(Interface): - def bar(self, *args): - raise NotImplementedError - - class MyEntity(AnyEntity): - __regid__ = 'MyEntity' - __implements__ = AnyEntity.__implements__ + (IFoo,) - - def bar(self, *args): - return sum(captain.age for captain in self.captains) - - class FooView(EntityView): - __regid__ = 'mycube.fooview' - __select__ = implements('IFoo') - - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - self.w('bar: %s' % entity.bar()) - -Converting to: - -.. sourcecode:: python - - class IFooAdapter(EntityAdapter): - __regid__ = 'IFoo' - __select__ = is_instance('MyEntity') - - def bar(self, *args): - return sum(captain.age for captain in self.entity.captains) - - class FooView(EntityView): - __regid__ = 'mycube.fooview' - __select__ = adaptable('IFoo') - - def cell_call(self, row, col): - entity = self.cw_rset.get_entity(row, col) - self.w('bar: %s' % entity.cw_adapt_to('IFoo').bar()) - -.. note:: - - When migrating an entity method to an adapter, the code can be moved as is - except for the `self` of the entity class, which in the adapter must become `self.entity`. - -Adapters defined in the library -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: cubicweb.entities.adapters - :members: - -More are defined in web/views.