doc/book/en/development/devrepo/hooks.rst
author Aurelien Campeas <aurelien.campeas@logilab.fr>
Mon, 12 Apr 2010 16:57:11 +0200
branchstable
changeset 5221 b851558456bb
parent 5220 42f854b6083d
child 5231 40f53867e332
permissions -rw-r--r--
[doc/book] remove merged chapter
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     1
.. -*- coding: utf-8 -*-
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     2
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     3
.. _hooks:
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     4
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
     5
Hooks and Operations
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
     6
====================
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
     7
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
     8
Generalities
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
     9
------------
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    10
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    11
Paraphrasing the `emacs`_ documentation, let us say that hooks are an
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    12
important mechanism for customizing an application. A hook is
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    13
basically a list of functions to be called on some well-defined
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    14
occasion (this is called `running the hook`).
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    15
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    16
.. _`emacs`: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    17
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    18
In CubicWeb, hooks are subclasses of the Hook class in
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    19
`server/hook.py`, implementing their own `call` method, and selected
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    20
over a set of pre-defined `events` (and possibly more conditions,
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    21
hooks being selectable AppObjects like views and components).
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    22
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    23
There are two families of events: data events and server events. In a
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    24
typical application, most of the Hooks are defined over data
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    25
events.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    26
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    27
The purpose of data hooks is to complement the data model as defined
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    28
in the schema.py, which is static by nature, with dynamic or value
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    29
driven behaviours. It is functionally equivalent to a `database
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    30
trigger`_, except that database triggers definition languages are not
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    31
standardized, hence not portable (for instance, PL/SQL works with
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    32
Oracle and PostgreSQL but not SqlServer nor Sqlite).
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    33
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    34
.. _`database trigger`: http://en.wikipedia.org/wiki/Database_trigger
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    35
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    36
Data hooks can serve the following purposes:
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    37
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    38
* enforcing constraints that the static schema cannot express
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    39
  (spanning several entities/relations, exotic value ranges and
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    40
  cardinalities, etc.)
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    41
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    42
* implement computed attributes
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    43
5221
b851558456bb [doc/book] remove merged chapter
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5220
diff changeset
    44
Operations are Hook-like objects that maye be created by Hooks and
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    45
scheduled to happen just before (or after) the `commit` event. Hooks
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    46
being fired immediately on data operations, it is sometime necessary
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    47
to delay the actual work down to a time where all other Hooks have
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    48
run, for instance a validation check which needs that all relations be
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    49
already set on an entity. Also while the order of execution of Hooks
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    50
is data dependant (and thus hard to predict), it is possible to force
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    51
an order on Operations.
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    52
5221
b851558456bb [doc/book] remove merged chapter
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5220
diff changeset
    53
Operations also may be used to process various side effects associated
b851558456bb [doc/book] remove merged chapter
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5220
diff changeset
    54
with a transaction such as filesystem udpates, mail notifications,
b851558456bb [doc/book] remove merged chapter
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5220
diff changeset
    55
etc.
b851558456bb [doc/book] remove merged chapter
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5220
diff changeset
    56
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    57
Operations are subclasses of the Operation class in `server/hook.py`,
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    58
implementing `precommit_event` and other standard methods (wholly
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    59
described later in this chapter).
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    60
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    61
Events
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    62
------
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    63
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    64
Hooks are mostly defined and used to handle `dataflow`_ operations. It
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    65
means as data gets in (entities added, updated, relations set or
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    66
unset), specific events are issued and the Hooks matching these events
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
    67
are called.
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    68
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    69
.. _`dataflow`: http://en.wikipedia.org/wiki/Dataflow
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    70
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    71
Below comes a list of the dataflow events related to entities operations:
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    72
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    73
* before_add_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    74
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    75
* before_update_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    76
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    77
* before_delete_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    78
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    79
* after_add_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    80
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    81
* after_update_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    82
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    83
* after_delete_entity
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    84
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    85
These define ENTTIES HOOKS. RELATIONS HOOKS are defined
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    86
over the following events:
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    87
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    88
* after_add_relation
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    89
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    90
* after_delete_relation
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    91
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    92
* before_add_relation
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    93
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    94
* before_delete_relation
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    95
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    96
This is an occasion to remind us that relations support the add/delete
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
    97
operation, but no update.
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    98
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
    99
Non data events also exist. These are called SYSTEM HOOKS.
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   100
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   101
* server_startup
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   102
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   103
* server_shutdown
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   104
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   105
* server_maintenance
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   106
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   107
* server_backup
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   108
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   109
* server_restore
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   110
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   111
* session_open
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   112
5191
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   113
* session_close
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   114
6d182c7d4392 [doc/book] begin chapter on Hooks/Operations
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2172
diff changeset
   115
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   116
Using dataflow Hooks
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   117
--------------------
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   118
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   119
XXX blabla
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   120
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   121
Validation Errors
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   122
~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   123
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   124
When a condition is not met in a Hook/Operation, it must raise a
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   125
`ValidationError`. Raising anything but a (subclass of)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   126
ValidationError is a programming error. Raising a ValidationError
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   127
entails aborting the current transaction.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   128
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   129
The ValidationError exception is used to convey enough information up
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   130
to the user interface. Hence its constructor is different from the
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   131
default Exception constructor. It accepts, positionally:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   132
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   133
* an entity eid,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   134
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   135
* a dict whose keys represent attribute (or relation) names and values
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   136
  an end-user facing message (hence properly translated) relating the
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   137
  problem.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   138
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   139
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   140
We will use a very simple example to show hooks usage. Let us start
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   141
with the following schema.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   142
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   143
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   144
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   145
   class Person(EntityType):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   146
       age = Int(required=True)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   147
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   148
An entity hook
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   149
~~~~~~~~~~~~~~
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   150
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   151
We would like to add a range constraint over a person's age. Let's
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   152
write an hook. It shall be placed into mycube/hooks.py. If this file
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   153
were to grow too much, we can easily have a mycube/hooks/... package
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   154
containing hooks in various modules.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   155
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   156
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   157
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   158
   from cubicweb import ValidationError
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   159
   from cubicweb.selectors import implements
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   160
   from cubicweb.server.hook import Hook
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   161
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   162
   class PersonAgeRange(Hook):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   163
        __regid__ = 'person_age_range'
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   164
        events = ('before_add_entity', 'before_update_entity')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   165
        __select__ = Hook.__select__ & implements('Person')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   166
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   167
        def __call__(self):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   168
            if 0 >= self.entity.age <= 120:
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   169
               return
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   170
            msg = self._cw._('age must be between 0 and 120')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   171
            raise ValidationError(self.entity.eid, {'age': msg})
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   172
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   173
Hooks being AppObjects like views, they have a __regid__ and a
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   174
__select__ class attribute. The base __select__ is augmented with an
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   175
`implements` selector matching the desired entity type. The `events`
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   176
tuple is used by the Hook.__select__ base selector to dispatch the
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   177
hook on the right events. In an entity hook, it is possible to
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   178
dispatch on any entity event (e.g. 'before_add_entity',
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   179
'before_update_entity') at once if needed.
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   180
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   181
Like all appobjects, hooks have the `self._cw` attribute which
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   182
represents the current session. In entity hooks, a `self.entity`
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   183
attribute is also present.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   184
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   185
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   186
A relation hook
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   187
~~~~~~~~~~~~~~~
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   188
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   189
Let us add another entity type with a relation to person (in
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   190
mycube/schema.py).
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   191
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   192
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   193
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   194
   class Company(EntityType):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   195
        name = String(required=True)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   196
        boss = SubjectRelation('Person', cardinality='1*')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   197
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   198
We would like to constrain the company's bosses to have a minimum
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   199
(legal) age. Let's write an hook for this, which will be fired when
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   200
the `boss` relation is established.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   201
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   202
.. sourcecode:: python
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   203
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   204
   class CompanyBossLegalAge(Hook):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   205
        __regid__ = 'company_boss_legal_age'
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   206
        events = ('before_add_relation',)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   207
        __select__ = Hook.__select__ & match_rtype('boss')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   208
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   209
        def __call__(self):
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   210
            boss = self._cw.entity_from_eid(self.eidto)
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   211
            if boss.age < 18:
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   212
                msg = self._cw._('the minimum age for a boss is 18')
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   213
                raise ValidationError(self.eidfrom, {'boss': msg})
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   214
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   215
We use the `match_rtype` selector to select the proper relation type.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   216
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   217
The essential difference with respect to an entity hook is that there
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   218
is no self.entity, but `self.eidfrom` and `self.eidto` hook attributes
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   219
which represent the subject and object eid of the relation.
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   220
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   221
Using Operations
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   222
----------------
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   223
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   224
Let's augment our example with a new `subsidiary_of` relation on Company.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   225
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   226
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   227
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   228
   class Company(EntityType):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   229
        name = String(required=True)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   230
        boss = SubjectRelation('Person', cardinality='1*')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   231
        subsidiary_of = SubjectRelation('Company', cardinality='*?')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   232
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   233
Base example
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   234
~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   235
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   236
We would like to check that there is no cycle by the `subsidiary_of`
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   237
relation. This is best achieved in an Operation since all relations
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   238
are likely to be set at commit time.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   239
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   240
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   241
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   242
    def check_cycle(self, session, eid, rtype, role='subject'):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   243
        parents = set([eid])
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   244
        parent = session.entity_from_eid(eid)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   245
        while parent.related(rtype, role):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   246
            parent = parent.related(rtype, role)[0]
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   247
            if parent.eid in parents:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   248
                msg = session._('detected %s cycle' % rtype)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   249
                raise ValidationError(eid, {rtype: msg})
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   250
            parents.add(parent.eid)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   251
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   252
    class CheckSubsidiaryCycleOp(Operation):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   253
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   254
        def precommit_event(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   255
            check_cycle(self.session, self.eidto, 'subsidiary_of')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   256
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   257
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   258
    class CheckSubsidiaryCycleHook(Hook):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   259
        __regid__ = 'check_no_subsidiary_cycle'
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   260
        events = ('after_add_relation',)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   261
        __select__ = Hook.__select__ & match_rtype('subsidiary_of')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   262
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   263
        def __call__(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   264
            CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   265
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   266
The operation is instantiated in the Hook.__call__ method.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   267
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   268
An operation always takes a session object as first argument
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   269
(accessible as `.session` from the operation instance), and optionally
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   270
all keyword arguments needed by the operation. These keyword arguments
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   271
will be accessible as attributes from the operation instance.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   272
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   273
Like in Hooks, ValidationError can be raised in Operations. Other
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   274
exceptions are programming errors.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   275
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   276
Notice how our hook will instantiate an operation each time the Hook
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   277
is called, i.e. each time the `subsidiary_of` relation is set.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   278
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   279
Using set_operation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   280
~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   281
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   282
There is an alternative method to schedule an Operation from a Hook,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   283
using the `set_operation` function.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   284
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   285
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   286
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   287
   class CheckSubsidiaryCycleHook(Hook):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   288
       __regid__ = 'check_no_subsidiary_cycle'
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   289
       events = ('after_add_relation',)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   290
       __select__ = Hook.__select__ & match_rtype('subsidiary_of')
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   291
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   292
       def __call__(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   293
           set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   294
                         CheckCycleOp, rtype=self.rtype)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   295
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   296
   class CheckSubsidiaryCycleOp(Operation):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   297
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   298
       def precommit_event(self):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   299
           for eid in self._cw.transaction_data['subsidiary_cycle_detection']:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   300
               check_cycle(self.session, eid, self.rtype)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   301
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   302
Here, we call set_operation with a session object, a specially forged
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   303
key, a value that is the actual payload of an individual operation (in
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   304
our case, the object of the subsidiary_of relation) , the class of the
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   305
Operation, and more optional parameters to give to the operation (here
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   306
the rtype which do not vary accross operations).
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   307
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   308
The body of the operation must then iterate over the values that have
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   309
been mapped in the transaction_data dictionary to the forged key.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   310
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   311
This mechanism is especially useful on two occasions (not shown in our
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   312
example):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   313
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   314
* massive data import (reduced memory consumption within a large
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   315
  transaction)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   316
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   317
* when several hooks need to instantiate the same operation (e.g. an
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   318
  entity and a relation hook).
5202
4a77da652759 [doc/book] more about hooks (simple examples with entities and relations)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5191
diff changeset
   319
5220
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   320
Operation: a small API overview
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   321
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   322
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   323
.. autoclass:: cubicweb.server.hook.Operation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   324
.. autoclass:: cubicweb.server.hook.LateOperation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   325
.. autofunction:: cubicweb.server.hook.set_operation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   326
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   327
Hooks writing rules
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   328
-------------------
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   329
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   330
Remainder
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   331
~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   332
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   333
Never, ever use the `entity.foo = 42` notation to update an entity. It
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   334
will not work.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   335
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   336
How to choose between a before and an after event ?
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   337
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   338
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   339
Before hooks give you access to the old attribute (or relation)
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   340
values. By definition the database is not yet updated in a before
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   341
hook.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   342
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   343
To access old and new values in an before_update_entity hook, one can
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   344
use the `server.hook.entity_oldnewvalue` function which returns a
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   345
tuple of the old and new values. This function takes an entity and an
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   346
attribute name as parameters.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   347
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   348
In a 'before_add|update_entity' hook the self.entity contains the new
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   349
values. One is allowed to further modify them before database
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   350
operations, using the dictionary notation.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   351
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   352
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   353
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   354
   self.entity['age'] = 42
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   355
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   356
This is because using self.entity.set_attributes(age=42) will
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   357
immediately update the database (which does not make sense in a
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   358
pre-database hook), and will trigger any existing
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   359
before_add|update_entity hook, thus leading to infinite hook loops or
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   360
such awkward situations.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   361
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   362
Beyond these specific cases, updating an entity attribute or relation
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   363
must *always* be done using `set_attributes` and `set_relations`
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   364
methods.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   365
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   366
(Of course, ValidationError will always abort the current transaction,
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   367
whetever the event).
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   368
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   369
Peculiarities of inlined relations
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   370
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   371
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   372
Some relations are defined in the schema as `inlined` (see
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   373
:ref:`RelationType` for details). In this case, they are inserted in
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   374
the database at the same time as entity attributes.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   375
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   376
Hence in the case of before_add_relation, such relations already exist
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   377
in the database.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   378
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   379
Edited attributes
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   380
~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   381
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   382
On udpates, it is possible to ask the `entity.edited_attributes`
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   383
variable whether one attribute has been updated.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   384
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   385
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   386
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   387
  if 'age' not in entity.edited_attribute:
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   388
      return
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   389
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   390
Deleted in transaction
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   391
~~~~~~~~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   392
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   393
The session object has a deleted_in_transaction method, which can help
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   394
writing deletion Hooks.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   395
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   396
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   397
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   398
   if self._cw.deleted_in_transaction(self.eidto):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   399
      return
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   400
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   401
Given this predicate, we can avoid scheduling an operation.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   402
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   403
Disabling hooks
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   404
~~~~~~~~~~~~~~~
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   405
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   406
It is sometimes convenient to disable some hooks. For instance to
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   407
avoid infinite Hook loops. One uses the `hooks_control` context
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   408
manager.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   409
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   410
This can be controlled more finely through the `category` Hook class
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   411
attribute.
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   412
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   413
.. sourcecode:: python
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   414
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   415
   with hooks_control(self.session, self.session.HOOKS_ALLOW_ALL, <category>):
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   416
       # ... do stuff
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   417
42f854b6083d [doc/book] complete chapter on hooks & ops
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5202
diff changeset
   418
.. autoclass:: cubicweb.server.session.hooks_control