server/hook.py
changeset 6279 42079f752a9c
parent 6147 95c604ec89bf
parent 6263 e91ac6e95116
child 6366 1806148d6ce8
equal deleted inserted replaced
6229:c4a70a5dd144 6279:42079f752a9c
   246 from warnings import warn
   246 from warnings import warn
   247 from logging import getLogger
   247 from logging import getLogger
   248 from itertools import chain
   248 from itertools import chain
   249 
   249 
   250 from logilab.common.decorators import classproperty
   250 from logilab.common.decorators import classproperty
   251 from logilab.common.deprecation import deprecated
   251 from logilab.common.deprecation import deprecated, class_renamed
   252 from logilab.common.logging_ext import set_log_methods
   252 from logilab.common.logging_ext import set_log_methods
   253 
   253 
   254 from cubicweb import RegistryNotFound
   254 from cubicweb import RegistryNotFound
   255 from cubicweb.vregistry import classid
   255 from cubicweb.vregistry import classid
   256 from cubicweb.cwvreg import CWRegistry, VRegistry
   256 from cubicweb.cwvreg import CWRegistry, VRegistry
   478                 self.call(self._cw, self.entity)
   478                 self.call(self._cw, self.entity)
   479 
   479 
   480 set_log_methods(Hook, getLogger('cubicweb.hook'))
   480 set_log_methods(Hook, getLogger('cubicweb.hook'))
   481 
   481 
   482 
   482 
   483 # base classes for relation propagation ########################################
   483 # abtract hooks for relation propagation #######################################
   484 
   484 # See example usage in hooks of the nosylist cube
   485 class PropagateSubjectRelationHook(Hook):
   485 
       
   486 class PropagateRelationHook(Hook):
   486     """propagate some `main_rtype` relation on entities linked as object of
   487     """propagate some `main_rtype` relation on entities linked as object of
   487     `subject_relations` or as subject of `object_relations` (the watched
   488     `subject_relations` or as subject of `object_relations` (the watched
   488     relations).
   489     relations).
   489 
   490 
   490     This hook ensure that when one of the watched relation is added, the
   491     This hook ensure that when one of the watched relation is added, the
   491     `main_rtype` relation is added to the target entity of the relation.
   492     `main_rtype` relation is added to the target entity of the relation.
       
   493 
       
   494     You usually want to use the :class:`match_rtype_sets` selector on concret
       
   495     classes.
   492     """
   496     """
   493     events = ('after_add_relation',)
   497     events = ('after_add_relation',)
   494 
   498 
   495     # to set in concrete class
   499     # to set in concrete class
   496     main_rtype = None
   500     main_rtype = None
   512             'SET E %s P WHERE X %s P, X eid %%(x)s, E eid %%(e)s, NOT E %s P'
   516             'SET E %s P WHERE X %s P, X eid %%(x)s, E eid %%(e)s, NOT E %s P'
   513             % (self.main_rtype, self.main_rtype, self.main_rtype),
   517             % (self.main_rtype, self.main_rtype, self.main_rtype),
   514             {'x': meid, 'e': seid})
   518             {'x': meid, 'e': seid})
   515 
   519 
   516 
   520 
   517 class PropagateSubjectRelationAddHook(Hook):
   521 class PropagateRelationAddHook(Hook):
   518     """propagate to entities at the end of watched relations when a `main_rtype`
   522     """Propagate to entities at the end of watched relations when a `main_rtype`
   519     relation is added
   523     relation is added.
       
   524 
       
   525     `subject_relations` and `object_relations` attributes should be specified on
       
   526     subclasses and are usually shared references with attributes of the same
       
   527     name on :class:`PropagateRelationHook`.
       
   528 
       
   529     Because of those shared references, you can use `skip_subject_relations` and
       
   530     `skip_object_relations` attributes when you don't want to propagate to
       
   531     entities linked through some particular relations.
   520     """
   532     """
   521     events = ('after_add_relation',)
   533     events = ('after_add_relation',)
   522 
   534 
   523     # to set in concrete class
   535     # to set in concrete class (mandatory)
   524     subject_relations = None
   536     subject_relations = None
   525     object_relations = None
   537     object_relations = None
       
   538     # to set in concrete class (optionaly)
       
   539     skip_subject_relations = ()
       
   540     skip_object_relations = ()
   526 
   541 
   527     def __call__(self):
   542     def __call__(self):
   528         eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0])
   543         eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0])
   529         execute = self._cw.execute
   544         execute = self._cw.execute
   530         for rel in self.subject_relations:
   545         for rel in self.subject_relations:
   531             if rel in eschema.subjrels:
   546             if rel in eschema.subjrels and not rel in self.skip_subject_relations:
   532                 execute('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   547                 execute('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   533                         'X %s R, NOT R %s P' % (self.rtype, rel, self.rtype),
   548                         'X %s R, NOT R %s P' % (self.rtype, rel, self.rtype),
   534                         {'x': self.eidfrom, 'p': self.eidto})
   549                         {'x': self.eidfrom, 'p': self.eidto})
   535         for rel in self.object_relations:
   550         for rel in self.object_relations:
   536             if rel in eschema.objrels:
   551             if rel in eschema.objrels and not rel in self.skip_object_relations:
   537                 execute('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   552                 execute('SET R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   538                         'R %s X, NOT R %s P' % (self.rtype, rel, self.rtype),
   553                         'R %s X, NOT R %s P' % (self.rtype, rel, self.rtype),
   539                         {'x': self.eidfrom, 'p': self.eidto})
   554                         {'x': self.eidfrom, 'p': self.eidto})
   540 
   555 
   541 
   556 
   542 class PropagateSubjectRelationDelHook(Hook):
   557 class PropagateRelationDelHook(PropagateRelationAddHook):
   543     """propagate to entities at the end of watched relations when a `main_rtype`
   558     """Propagate to entities at the end of watched relations when a `main_rtype`
   544     relation is deleted
   559     relation is deleted.
       
   560 
       
   561     This is the opposite of the :class:`PropagateRelationAddHook`, see its
       
   562     documentation for how to use this class.
   545     """
   563     """
   546     events = ('after_delete_relation',)
   564     events = ('after_delete_relation',)
   547 
       
   548     # to set in concrete class
       
   549     subject_relations = None
       
   550     object_relations = None
       
   551 
   565 
   552     def __call__(self):
   566     def __call__(self):
   553         eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0])
   567         eschema = self._cw.vreg.schema.eschema(self._cw.describe(self.eidfrom)[0])
   554         execute = self._cw.execute
   568         execute = self._cw.execute
   555         for rel in self.subject_relations:
   569         for rel in self.subject_relations:
   556             if rel in eschema.subjrels:
   570             if rel in eschema.subjrels and not rel in self.skip_subject_relations:
   557                 execute('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   571                 execute('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   558                         'X %s R' % (self.rtype, rel),
   572                         'X %s R' % (self.rtype, rel),
   559                         {'x': self.eidfrom, 'p': self.eidto})
   573                         {'x': self.eidfrom, 'p': self.eidto})
   560         for rel in self.object_relations:
   574         for rel in self.object_relations:
   561             if rel in eschema.objrels:
   575             if rel in eschema.objrels and not rel in self.skip_object_relations:
   562                 execute('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   576                 execute('DELETE R %s P WHERE X eid %%(x)s, P eid %%(p)s, '
   563                         'R %s X' % (self.rtype, rel),
   577                         'R %s X' % (self.rtype, rel),
   564                         {'x': self.eidfrom, 'p': self.eidto})
   578                         {'x': self.eidfrom, 'p': self.eidto})
       
   579 
       
   580 
       
   581 PropagateSubjectRelationHook = class_renamed(
       
   582     'PropagateSubjectRelationHook', PropagateRelationHook,
       
   583     '[3.9] PropagateSubjectRelationHook has been renamed to PropagateRelationHook')
       
   584 PropagateSubjectRelationAddHook = class_renamed(
       
   585     'PropagateSubjectRelationAddHook', PropagateRelationAddHook,
       
   586     '[3.9] PropagateSubjectRelationAddHook has been renamed to PropagateRelationAddHook')
       
   587 PropagateSubjectRelationDelHook = class_renamed(
       
   588     'PropagateSubjectRelationDelHook', PropagateRelationDelHook,
       
   589     '[3.9] PropagateSubjectRelationDelHook has been renamed to PropagateRelationDelHook')
   565 
   590 
   566 
   591 
   567 # abstract classes for operation ###############################################
   592 # abstract classes for operation ###############################################
   568 
   593 
   569 class Operation(object):
   594 class Operation(object):