doc/book/en/development/datamodel/definition.rst
brancholdstable
changeset 5422 0865e1e90674
parent 4985 02b52bf9f5f8
parent 5421 8167de96c523
child 5424 8ecbcbff9777
--- a/doc/book/en/development/datamodel/definition.rst	Wed Mar 24 10:23:31 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,512 +0,0 @@
- .. -*- coding: utf-8 -*-
-
-Yams *schema*
--------------
-
-The **schema** is the core piece of a *CubicWeb* instance as it defines
-the handled data model. It is based on entity types that are either already
-defined in the *CubicWeb* standard library; or more specific types defined
-in cubes. The schema for a cube is defined in a :file:schema.py file or in
-one or more Python files under the :file:`schema` directory (python package).
-
-At this point, it is important to make clear the difference between
-*relation type* and *relation definition*: a *relation type* is only a relation
-name with potentially other additionnal properties (see below), whereas a
-*relation definition* is a complete triplet
-"<subject entity type> <relation type> <object entity type>".
-A relation type could have been implied if none is related to a
-relation definition of the schema.
-
-Also, it should be clear that to properly handle data migration, an instance'schema
-is stored in the database, so the python schema file used to defined it are only readen
-when the instance is created or upgraded.
-
-The following built-in types are available : `String`, `Int`, `Float`,
-`Decimal`, `Boolean`, `Date`, `Datetime`, `Time`, `Interval`, `Byte`
-and `Password`.
-
-You'll also have access to :ref:`base cubicweb entity types <CWBaseEntityTypes>`.
-
-The instance schema is accessible through the .schema attribute of the
-`vregistry`.  It's an instance of :class:`cubicweb.schema.Schema`, which
-extends :class:`yams.schema.Schema`.
-
-:note:
-  In previous yams versions, almost all classes where available without
-  any import, but the should now be explicitely imported.
-
-
-Entity type
-~~~~~~~~~~~
-It's an instance of :class:`yams.schema.EntitySchema`. Each entity types has
-a set of attributes and relation and some permissions, defining who can add, read,
-update or delete entities of this type.
-
-XXX yams inheritance
-
-Relation type
-~~~~~~~~~~~~~
-It's an instance of :class:`yams.schema.RelationSchema`. A relation type is simply
-a semantic definition of a kind of relationship that may occurs in your application.
-
-It's important to choose a good name, at least to avoid conflicts with some semantically
-different relation defined in other cubes (since we've no namespace yet).
-
-A relation type hold the following properties (which are hence shared between all
-relation definitions of that type):
-
-* `inlined` : boolean handling the physical optimization for archiving
-  the relation in the subject entity table, instead of creating a specific
-  table for the relation. This applies to relations where cardinality
-  of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
-  definitions.
-
-* `symmetric` : boolean indicating that the relation is symmetrical, which
-  means that `X relation Y` implies `Y relation X`.
-
-
-Relation definition
-~~~~~~~~~~~~~~~~~~~
-It's an instance of :class:`yams.schema.RelationDefinition`. It is a complete triplet
-"<subject entity type> <relation type> <object entity type>".
-
-Properties
-``````````
-
-* Optional properties for attributes and relations :
-
-  - `description` : a string describing an attribute or a relation. By default
-    this string will be used in the editing form of the entity, which means
-    that it is supposed to help the end-user and should be flagged by the
-    function `_` to be properly internationalized.
-
-  - `constraints` : a list of conditions/constraints that the relation has to
-    satisfy (c.f. `Constraints`_)
-
-  - `cardinality` : a two character string which specify the cardinality of the
-    relation. The first character defines the cardinality of the relation on
-    the subject, and the second on the object. When a relation can have
-    multiple subjects or objects, the cardinality applies to all,
-    not on a one-to-one basis (so it must be consistent...). The possible
-    values are inspired from regular expression syntax :
-
-    * `1`: 1..1
-    * `?`: 0..1
-    * `+`: 1..n
-    * `*`: 0..n
-
-* optional properties for attributes :
-
-  - `unique` : boolean indicating if the value of the attribute has to be unique
-    or not within all entities of the same type (false by default)
-
-  - `indexed` : boolean indicating if an index needs to be created for this
-    attribute in the database (false by default). This is useful only if
-    you know that you will have to run numerous searches on the value of this
-    attribute.
-
-  - `default` : default value of the attribute. In case of date types, the values
-    which could be used correspond to the RQL keywords `TODAY` and `NOW`.
-
-* optional properties of type `String` :
-
-  - `fulltextindexed` : boolean indicating if the attribute is part of
-    the full text index (false by default) (*applicable on the type `Byte`
-    as well*)
-
-  - `internationalizable` : boolean indicating if the value of the attribute
-    is internationalizable (false by default)
-
-* optional properties for relations :
-
-  - `composite` : string indicating that the subject (composite == 'subject')
-    is composed of the objects of the relations. For the opposite case (when
-    the object is composed of the subjects of the relation), we just set
-    'object' as value. The composition implies that when the relation
-    is deleted (so when the composite is deleted, at least), the composed are also deleted.
-
-  - `fti_container`: XXX feed me
-
-Constraints
-```````````
-
-By default, the available constraint types are :
-
-General Constraints
-......................
-
-* `SizeConstraint` : allows to specify a minimum and/or maximum size on
-  string (generic case of `maxsize`)
-
-* `BoundConstraint` : allows to specify a minimum and/or maximum value on
-  numeric types
-
-* `UniqueConstraint` : identical to "unique=True"
-
-* `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
-
-XXX Attribute, TODAY, NOW
-
-RQL Based Constraints
-......................
-
-RQL based constraints may take three arguments. The first one is the ``WHERE``
-clause of a RQL query used by the constraint. The second argument ``mainvars``
-is the ``Any`` clause of the query. By default this include `S` reserved for the
-subject of the relation and `O` for the object. Additional variables could be
-specified using ``mainvars``. The argument expects a single string with all
-variable's name separated by spaces. The last one, ``msg``, is the error message
-displayed when the constraint fails. As RQLVocabularyConstraint never fails the
-third argument is not available.
-
-* `RQLConstraint` : allows to specify a RQL query that has to be satisfied
-  by the subject and/or the object of relation. In this query the variables
-  `S` and `O` are reserved for the entities subject and object of the
-  relation.
-
-* `RQLVocabularyConstraint` : similar to the previous type of constraint except
-  that it does not express a "strong" constraint, which means it is only used to
-  restrict the values listed in the drop-down menu of editing form, but it does
-  not prevent another entity to be selected.
-
-* `RQLUniqueConstraint` : allows to the specify a RQL query that ensure that an
-  attribute is unique in a specific context. The Query must **never** return more
-  than a single result to be satisfied. In this query the variables `S` is
-  reserved for the entity subject of the relation. The other variable should be
-  specified with the second constructor argument (mainvars). This constraints
-  should be used when UniqueConstraint doesn't fit. Here is a simple example ::
-
-    # Check that in the same Workflow each state's name is unique.  Using
-    # UniqueConstraint (or unique=True) here would prevent states in different
-    # workflows to have the same name.
-
-    # With: State S, Workflow W, String N ; S state_of W, S name N
-
-    RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
-                        mainvars='Y',
-                        msg=_('workflow already have a state of that name'))
-
-
-
-* `RQLUniqueConstraint` : allows to the specify a RQL query that ensure that an
-  attribute is unique in a specific context. The Query must **never** return more
-  than a single result to be satisfied. In this query the variables `S` is
-  reserved for the entity subject of the relation. The other variable should be
-  specified with the second constructor argument (mainvars). This constraints
-  should be used when UniqueConstraint doesn't fit. Here is a simple example ::
-
-    # Check that in the same Workflow each state's name is unique.  Using
-    # UniqueConstraint (or unique=True) here would prevent states in different
-    # workflows to have the same name.
-
-    # With: State S, Workflow W, String N ; S state_of W, S name N
-
-    RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
-                        mainvars='Y',
-                        msg=_('workflow already have a state of that name'))
-
-
-
-XXX note about how to add new constraint
-
-.. _securitymodel:
-
-
-The security model
-~~~~~~~~~~~~~~~~~~
-
-The security model of `cubicWeb` is based on `Access Control List`.
-The main principles are:
-
-* users and groups of users
-* a user belongs to at least one group of user
-* permissions (read, update, create, delete)
-* permissions are assigned to groups (and not to users)
-
-For *CubicWeb* in particular:
-
-* we associate rights at the enttities/relations schema level
-* for each entity, we distinguish four kind of permissions: read,
-  add, update and delete
-* for each relation, we distinguish three kinds of permissions: read,
-  add and delete (we can not modify a relation)
-* the basic groups are: Administrators, Users and Guests
-* by default, users belong to the group Users
-* there is a virtual group called `Owners` to which we
-  can associate only deletion and update permissions
-* we can not add users to the `Owners` group, they are
-  implicitly added to it according to the context of the objects
-  they own
-* the permissions of this group are only checked on update/deletion
-  actions if all the other groups the user belongs to does not provide
-  those permissions
-
-Setting permissions is done with the attribute `__permissions__` of entities and
-relation types. It defines a dictionary where the keys are the access types
-(action), and the values are the authorized groups or expressions.
-
-For an entity type, the possible actions are `read`, `add`, `update` and
-`delete`.
-
-For a relation type, the possible actions are `read`, `add`, and `delete`.
-
-For each access type, a tuple indicates the name of the authorized groups and/or
-one or multiple RQL expressions to satisfy to grant access. The access is
-provided if the user is in one of the listed groups or one of if the RQL condition
-is satisfied.
-
-The standard user groups
-````````````````````````
-
-* `guests`
-
-* `users`
-
-* `managers`
-
-* `owners` : virtual group corresponding to the entity's owner.
-  This can only be used for the actions `update` and `delete` of an entity
-  type.
-
-It is also possible to use specific groups if they are defined in the
-precreate of the cube (``migration/precreate.py``). Defining groups in
-postcreate or even later makes them NOT available for security
-purposes (in this case, an `sync_schema_props_perms` command have to
-be issued in a CubicWeb shell).
-
-
-Use of RQL expression for write permissions
-```````````````````````````````````````````
-It is possible to define RQL expression to provide update permission
-(`add`, `delete` and `update`) on relation and entity types.
-
-RQL expression for entity type permission :
-
-* you have to use the class `ERQLExpression`
-
-* the used expression corresponds to the WHERE statement of an RQL query
-
-* in this expression, the variables X and U are pre-defined references
-  respectively on the current entity (on which the action is verified) and
-  on the user who send the request
-
-* it is possible to use, in this expression, a special relation
-  "has_<ACTION>_permission" where the subject is the user and the
-  object is any variable, meaning that the user needs to have
-  permission to execute the action <ACTION> on the entities related
-  to this variable
-
-For RQL expressions on a relation type, the principles are the same except
-for the following :
-
-* you have to use the class `RRQLExpression` in the case of a non-final relation
-
-* in the expression, the variables S, O and U are pre-defined references
-  to respectively the subject and the object of the current relation (on
-  which the action is being verified) and the user who executed the query
-
-* we can also define rights over attributes of an entity (non-final relation),
-  knowing that :
-
-  - to define RQL expression, we have to use the class `ERQLExpression`
-    in which X represents the entity the attribute belongs to
-
-  - the permissions `add` and `delete` are equivalent. Only `add`/`read`
-    are actually taken in consideration.
-
-:Note on the use of RQL expression for `add` permission:
-
-  Potentially, the use of an RQL expression to add an entity or a
-  relation can cause problems for the user interface, because if the
-  expression uses the entity or the relation to create, then we are
-  not able to verify the permissions before we actually add the entity
-  (please note that this is not a problem for the RQL server at all,
-  because the permissions checks are done after the creation). In such
-  case, the permission check methods (CubicWebEntitySchema.check_perm
-  and has_perm) can indicate that the user is not allowed to create
-  this entity but can obtain the permission.
-  To compensate this problem, it is usually necessary, for such case,
-  to use an action that reflects the schema permissions but which enables
-  to check properly the permissions so that it would show up if necessary.
-
-
-Use of RQL expression for reading rights
-````````````````````````````````````````
-
-The principles are the same but with the following restrictions :
-
-* we can not use `RRQLExpression` on relation types for reading
-
-* special relations "has_<ACTION>_permission" can not be used
-
-
-
-
-Defining your schema using yams
--------------------------------
-
-Entity type definition
-~~~~~~~~~~~~~~~~~~~~~~
-
-An entity type is defined by a Python class which inherits from `EntityType`.
-The class definition contains the description of attributes and relations
-for the defined entity type.
-The class name corresponds to the entity type name. It is exepected to be
-defined in the module ``mycube.schema``.
-
-When defining a schema using python files, you may use the following shortcuts:
-
-- `required` : boolean indicating if the attribute is required, eg subject cardinality is '1'
-
-- `vocabulary` : specify static possible values of an attribute
-
-- `maxsize` : integer providing the maximum size of a string (no limit by default)
-
-For example:
-
-.. sourcecode:: python
-
-  class Person(EntityType):
-    """A person with the properties and the relations necessary for my
-    application"""
-
-    last_name = String(required=True, fulltextindexed=True)
-    first_name = String(required=True, fulltextindexed=True)
-    title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
-    date_of_birth = Date()
-    works_for = SubjectRelation('Company', cardinality='?*')
-
-
-The entity described above defines three attributes of type String,
-last_name, first_name and title, an attribute of type Date for the date of
-birth and a relation that connects a `Person` to another entity of type
-`Company` through the semantic `works_for`.
-
-The name of the Python attribute corresponds to the name of the attribute
-or the relation in *CubicWeb* application.
-
-An attribute is defined in the schema as follows::
-
-    attr_name = attr_type(properties)
-
-where `attr_type` is one of the type listed above and `properties` is
-a list of the attribute needs to statisfy (see `Properties`_
-for more details).
-
-
-* relations can be defined by using `ObjectRelation` or `SubjectRelation`.
-  The first argument of `SubjectRelation` or `ObjectRelation` gives respectively
-  the object/subject entity type of the relation. This could be :
-
-  * a string corresponding to an entity type
-
-  * a tuple of string corresponding to multiple entity types
-
-  * special string such as follows :
-
-    - "**" : all types of entities
-    - "*" : all types of non-meta entities
-    - "@" : all types of meta entities but not system entities (e.g. used for
-      the basic schema description)
-
-* it is possible to use the attribute `meta` to flag an entity type as a `meta`
-  (e.g. used to describe/categorize other entities)
-
-*Note* : if you end up with an `if` in the definition of your entity, this probably
-means that you need two separate entities that implement the `ITree` interface and
-get the result from `.children()` which ever entity is concerned.
-
-Inheritance
-```````````
-XXX feed me
-
-
-Definition of relations
-~~~~~~~~~~~~~~~~~~~~~~~
-
-XXX add note about defining relation type / definition
-
-A relation is defined by a Python class heriting `RelationType`. The name
-of the class corresponds to the name of the type. The class then contains
-a description of the properties of this type of relation, and could as well
-contain a string for the subject and a string for the object. This allows to create
-new definition of associated relations, (so that the class can have the
-definition properties from the relation) for example ::
-
-  class locked_by(RelationType):
-    """relation on all entities indicating that they are locked"""
-    inlined = True
-    cardinality = '?*'
-    subject = '*'
-    object = 'CWUser'
-
-In the case of simultaneous relations definitions, `subject` and `object`
-can both be equal to the value of the first argument of `SubjectRelation`
-and `ObjectRelation`.
-
-When a relation is not inlined and not symmetrical, and it does not require
-specific permissions, its definition (by using `SubjectRelation` and
-`ObjectRelation`) is all we need.
-
-
-Definition of permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-The entity type `CWPermission` from the standard library
-allows to build very complex and dynamic security architectures. The schema of
-this entity type is as follow :
-
-.. sourcecode:: python
-
-    class CWPermission(EntityType):
-        """entity type that may be used to construct some advanced security configuration
-        """
-        name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
- require_group = SubjectRelation('CWGroup', cardinality='+*',
-                                        description=_('groups to which the permission is granted'))
- require_state = SubjectRelation('State',
-                                        description=_("entity's state in which the permission is applicable"))
-        # can be used on any entity
- require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
-                                            description=_("link a permission to the entity. This "
-                                                          "permission should be used in the security "
-                                                          "definition of the entity's type to be useful."))
-
-
-Example of configuration:
-
-.. sourcecode:: python
-
-    class Version(EntityType):
-        """a version is defining the content of a particular project's release"""
-
-        __permissions__ = {'read':   ('managers', 'users', 'guests',),
-                           'update': ('managers', 'logilab', 'owners',),
-                           'delete': ('managers', ),
-                           'add':    ('managers', 'logilab',
-                                       ERQLExpression('X version_of PROJ, U in_group G,'
-                                                 'PROJ require_permission P, P name "add_version",'
-                                                 'P require_group G'),)}
-
-
-    class version_of(RelationType):
-        """link a version to its project. A version is necessarily linked to one and only one project.
-        """
-        __permissions__ = {'read':   ('managers', 'users', 'guests',),
-                           'delete': ('managers', ),
-                           'add':    ('managers', 'logilab',
-                                  RRQLExpression('O require_permission P, P name "add_version",'
-                                                 'U in_group G, P require_group G'),)
-                       }
-        inlined = True
-
-
-This configuration indicates that an entity `CWPermission` named
-"add_version" can be associated to a project and provides rights to create
-new versions on this project to specific groups. It is important to notice that :
-
-* in such case, we have to protect both the entity type "Version" and the relation
-  associating a version to a project ("version_of")
-
-* because of the genericity of the entity type `CWPermission`, we have to execute
-  a unification with the groups and/or the states if necessary in the expression
-  ("U in_group G, P require_group G" in the above example)