doc/book/en/A03a-concepts.en.txt
author sylvain.thenault@logilab.fr
Fri, 17 Apr 2009 16:55:37 +0200
branchtls-sprint
changeset 1398 5fe84a5f7035
parent 1221 d474534fd04d
permissions -rw-r--r--
rename internal entity types to have CW prefix instead of E

.. -*- coding: utf-8 -*-

Concepts
--------

This section aims to provide you the keys of success with `CubicWeb`
by clarifying the terms specific to our framework.

Global architecture
~~~~~~~~~~~~~~~~~~~
.. image:: images/archi_globale.en.png


`CubicWeb` framework is a server/client application framework. Those two
parts communicate through RQL (`CubicWeb` query language implementation)
and ResultSet (which will be explained in :ref:`TermsVocabulary`).

The server manages all interactions with sources.


.. note::
  Usually, the client and server sides are integrated in the same
  process and interact directly, without the need for distant
  calls using Pyro. But, it is important to note that those two
  sides, client/server, are disjointed and it is possible to execute
  a couple of calls in distinct processes to balance the load of
  your web site on one or more machines.

.. _TermsVocabulary:

Terms and vocabulary
~~~~~~~~~~~~~~~~~~~~~

`CubicWeb` defines its own terminology. To make sure there is no confusion
while reading this book, we strongly recommand you take time to go through
the following definitions that are the basics to understand while
developing with `CubicWeb`.

*schema*
  The schema defines the data model of an application based on entities
  and relations, modeled with a comprehensive language made of Python
  classes based on `yams`_ library. This is the core piece
  of an application. It is initially defined in the file system and is
  stored in the database at the time an instance is created. `CubicWeb`
  provides a certain number of system entities included automatically    
  (necessary for the core of `CubicWeb`) and a library of
  cubes (which defined application entities) that can be explicitely
  included if necessary.

*entity type*
  An entity type is a set of attributes; the essential attribute of
  an entity is its key, named eid.

*relation type*
  Entities are linked to each others by relations. In `CubicWeb`
  relations are binary: by convention we name the first item of
  a relation the `subject` and the second the `object`.

*final entity type*
  Final types correspond to the basic types such as string of characters,
  integers... Those types have a main property which is that they can
  only be used as `object` of a relation. The attributes of an entity
  (non final) are entities (finals).

*final relation type*
  A relation is said final if its `object` is a final type. This is equivalent
  to an entity attribute.

*relation definition*
  A relation definition is a 3-uple (subject entity type, relation type, object
  entity type), with an associated set of property such as cardinality, constraints...

*repository*
  This is the RQL server side of `CubicWeb`. Be carefull not to get
  confused with a Mercurial repository or a debian repository.

*source*
  A data source is a container of data (SGBD, LDAP directory, `Google
  App Engine`'s datastore ...) integrated in the
  `CubicWeb` repository. This repository has at least one source, `system` which
  contains the schema of the application, plain-text index and other
  vital informations for the system.

*configuration*
  It is possible to create different configurations for an instance:

  - ``repository`` : repository only, accessible for clients using Pyro
  - ``twisted`` : web interface only, access the repository using Pyro
  - ``all-in-one`` : web interface and repository in a single process.
     The repository could be or not accessible using Pyro.

*cube*
  A cube is a model grouping one or multiple data types and/or views
  to provide a specific functionality or a complete `CubicWeb` application
  potentially using other cubes. The available cubes are located in the file
  system at `/path/to/forest/cubicweb/cubes` for a Mercurial forest installation.
  For a debian packages installation they will be located in
  `/usr/share/cubicweb/cubes`.
  Larger applications can be built quite fast by importing cubes,
  adding entities and relationships, overriding the
  *views* that display the cubes or by editing informations not provided by
  the cubes.

*instance*
  An instance is a specific installation of one or multiple cubes. All the required
  configuration files necessary for the well being of your web application
  are grouped in an instance. This will refer to the cube(s) your application
  is based on.
  For example logilab.org and our intranet are two instances of a single
  cube "jpl", developped internally.
  The instances are defined in the directory `/etc/cubicweb.d`.

*application*
  The term application is sometimes used to talk about an instance
  and sometimes to talk of a cube depending on the context.
  So we would like to avoid using this term and try to use *cube* and
  *instance* instead.

*result set*
  This object contains the results of an RQL query sent to the source
  and informations on the query.

*Pyro*
  `Python Remote Object`_, distributed objects system similar to Java's RMI
  (Remote Method Invocation), which can be used for the dialog between the web
  side of the framework and the RQL repository.

*query language*
  A full-blown query language named RQL is used to formulate requests
  to the database or any sources such as LDAP or `Google App Engine`'s
  datastore.

*views*
  A view is applied to a `result set` to present it as HTML, XML,
  JSON, CSV, etc. Views are implemented as Python classes. There is no
  templating language.

*generated user interface*
  A user interface is generated on-the-fly from the schema definition:
  entities can be created, displayed, updated and deleted. As display
  views are not very fancy, it is usually necessary to develop your
  own. Any generated view can be overridden by defining a new one with
  the same identifier.

*rql*
 Relation Query Language in order to emphasize the way of browsing relations.
 This query language is inspired by SQL but is on a higher level;
 its implementation generates SQL.


.. _`Python Remote Object`: http://pyro.sourceforge.net/
.. _`yams`: http://www.logilab.org/project/yams/


`CubicWeb` engine
~~~~~~~~~~~~~~~~~

The engine in `CubicWeb` is a set of classes managing a set of objects loaded
dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamic objects,
based on the schema or the library, are building the final application.
The different dynamic components are for example:

* client and server side

  - entities definition, containing the logic which enables application data manipulation

* client side

  - *views*, or more specifically

    - boxes
    - header and footer
    - forms
    - page templates

  - *actions*
  - *controllers*

* server side

  - notification hooks
  - notification views

The components of the engine are:

* a frontal web (only twisted is available so far), transparent for dynamic objects
* an object that encapsulates the configuration
* a `registry` (`cubicweb.cwvreg`) containing the dynamic objects loaded automatically

Every *appobject* may access to the instance configuration using its *config* attribute
and to the registry using its *vreg* attribute.

API Python/RQL
~~~~~~~~~~~~~~

The Python API developped to interface with RQL is inspired from the standard db-api,
with a Connection object having the methods cursor, rollback and commit essentially.
The most important method is the `execute` method of a cursor :

`execute(rqlstring, args=None, eid_key=None, build_descr=True)`

:rqlstring: the RQL query to execute (unicode)
:args: if the query contains substitutions, a dictionary containing the values to use
:eid_key:
   an implementation detail of the RQL cache implies that if a substitution
   is used to introduce an eid *susceptible to raise the ambiguities in the query
   type resolution*, then we have to specify the corresponding key in the dictionary
   through this argument


The `Connection` object owns the methods `commit` and `rollback`. You *should
never need to use them* during the development of the web interface based on
the `CubicWeb` framework as it determines the end of the transaction depending
on the query execution success.

.. note::
  While executing update queries (SET, INSERT, DELETE), if a query generates
  an error related to security, a rollback is automatically done on the current
  transaction.


The `Request` class (`cubicweb.web`)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A request instance is created when an HTTP request is sent to the web server.
It contains informations such as form parameters, user authenticated, etc.

**Globally, a request represents a user query, either through HTTP or not
(we also talk about RQL queries on the server side for example).**

An instance of `Request` has the following attributes:

* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
  user
* `form`, dictionary containing the values of a web form
* `encoding`, character encoding to use in the response

But also:

:Session data handling:
  * `session_data()`, returns a dictionary containing all the session data
  * `get_session_data(key, default=None)`, returns a value associated to the given
    key or the value `default` if the key is not defined
  * `set_session_data(key, value)`, assign a value to a key
  * `del_session_data(key)`,  suppress the value associated to a key


:Cookies handling:
  * `get_cookie()`, returns a dictionary containing the value of the header
    HTTP 'Cookie'
  * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
    with a minimal 5 minutes length of duration by default (`maxage` = None
    returns a *session* cookie which will expire when the user closes the browser
    window)
  * `remove_cookie(cookie, key)`, forces a value to expire

:URL handling:
  * `url()`, returns the full URL of the HTTP request
  * `base_url()`, returns the root URL of the web application
  * `relative_path()`, returns the relative path of the request

:And more...:
  * `set_content_type(content_type, filename=None)`, adds the header HTTP
    'Content-Type'
  * `get_header(header)`, returns the value associated to an arbitrary header
    of the HTTP request
  * `set_header(header, value)`, adds an arbitrary header in the response
  * `cursor()` returns a RQL cursor on the session
  * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
  * `property_value(key)`, properties management (`CWProperty`)
  * dictionary `data` to store data to share informations between components
    *while a request is executed*

Please note that this class is abstract and that a concrete implementation
will be provided by the *frontend* web used (in particular *twisted* as of
today). For the views or others that are executed on the server side,
most of the interface of `Request` is defined in the session associated
to the client.

The `AppObject` class
~~~~~~~~~~~~~~~~~~~~~

In general:

* we do not inherit directly from this class but from a more specific
  class such as `AnyEntity`, `EntityView`, `AnyRsetView`,
  `Action`...

* to be recordable, a subclass has to define its own register (attribute
  `__registry__`) and its identifier (attribute `id`). Usually we do not have
  to take care of the register, only the identifier `id`.

We can find a certain number of attributes and methods defined in this class
and common to all the application objects.

At the recording, the following attributes are dynamically added to
the *subclasses*:

* `vreg`, the `vregistry` of the application
* `schema`, the application schema
* `config`, the application configuration

We also find on instances, the following attributes:

* `req`, `Request` instance
* `rset`, the *result set* associated to the object if necessary
* `cursor`, rql cursor on the session


:URL handling:
  * `build_url(method=None, **kwargs)`, returns an absolute URL based on
    the given arguments. The *controller* supposed to handle the response,
    can be specified through the special parameter `method` (the connection
    is theoretically done automatically :).

  * `datadir_url()`, returns the directory of the application data
    (contains static files such as images, css, js...)

  * `base_url()`, shortcut to `req.base_url()`

  * `url_quote(value)`, version *unicode safe* of the function `urllib.quote`

:Data manipulation:

  * `etype_rset(etype, size=1)`, shortcut to `vreg.etype_rset()`

  * `eid_rset(eid, rql=None, descr=True)`, returns a *result set* object for
    the given eid
  * `entity(row, col=0)`, returns the entity corresponding to the data position
    in the *result set* associated to the object

  * `complete_entity(row, col=0, skip_bytes=True)`, is equivalent to `entity` but
    also call the method `complete()` on the entity before returning it

:Data formatting:
  * `format_date(date, date_format=None, time=False)` returns a string for a
    mx date time according to application's configuration
  * `format_time(time)` returns a string for a mx date time according to
    application's configuration

:And more...:

  * `external_resource(rid, default=_MARKER)`, access to a value defined in the
    configuration file `external_resource`

  * `tal_render(template, variables)`, renders a precompiled page template with
    variables in the given dictionary as context

.. note::
  When we inherit from `AppObject` (even not directly), you *always* have to use
  **super()** to get the methods and attributes of the superclasses, and not
  use the class identifier.
  For example, instead of writting: ::

      class Truc(PrimaryView):
          def f(self, arg1):
              PrimaryView.f(self, arg1)

  You'd better write: ::

      class Truc(PrimaryView):
          def f(self, arg1):
              super(Truc, self).f(arg1)

.. _cubesConcepts:

Cubes
~~~~~

What is a cube ?
````````````````

A cube is a model grouping one or more entity types and/or views associated
in order to provide a specific feature or even a complete application using
other cubes.

You can decide to write your own set of cubes if you wish to re-use the
entity types you develop. Lots of cubes are available from the `CubicWeb
Forge`_ under a free software license.

.. _`CubicWeb Forge`: http://www.cubicweb.org/project/

.. _foundationsCube:

Standard structure for a cube
`````````````````````````````

A cube is structured as follows:

::

  mycube/
  |
  |-- data/
  |   |-- cubes.mycube.css
  |   |-- cubes.mycube.js
  |   `-- external_resources
  |
  |-- debian/
  |   |-- changelog
  |   |-- compat
  |   |-- control
  |   |-- copyright
  |   |-- cubicweb-mycube.prerm
  |   `-- rules
  |
  |-- entities.py
  |
  |-- i18n/
  |   |-- en.po
  |   `-- fr.po
  |
  |-- __init__.py
  |
  |-- MANIFEST.in
  |
  |-- migration/
  |   |-- postcreate.py
  |   `-- precreate.py
  |
  |-- __pkginfo__.py
  |
  |-- schema.py
  |
  |-- setup.py
  |
  |-- site_cubicweb.py
  |
  |-- hooks.py
  |
  |-- test/
  |   |-- data/
  |   |   `-- bootstrap_cubes
  |   |-- pytestconf.py
  |   |-- realdb_test_mycube.py
  |   `-- test_mycube.py
  |
  `-- views.py


We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
``schema.py`` or ``hooks.py``. For example, we could have:

::

  mycube/
  |
  |-- entities.py
  |-- hooks.py
  `-- views/
      |-- forms.py
      |-- primary.py
      `-- widgets.py


where :

* ``schema`` contains the schema definition (server side only)
* ``entities`` contains the entities definition (server side and web interface)
* ``sobjects`` contains hooks and/or views notifications (server side only)
* ``views`` contains the web interface components (web interface only)
* ``test`` contains tests related to the application (not installed)
* ``i18n`` contains message catalogs for supported languages (server side and
  web interface)
* ``data`` contains data files for static content (images, css, javascripts)
  ...(web interface only)
* ``migration`` contains initialization file for new instances (``postcreate.py``)
  and a file containing dependencies of the component depending on the version
  (``depends.map``)
* ``debian`` contains all the files managing debian packaging (you will find
  the usual files ``control``, ``rules``, ``changelog``... not installed)
* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
  and the current version (server side and web interface) or sub-cubes used by
  the cube.


At least you should have:

* the file ``__pkginfo__.py``
* the schema definition
  XXX false, we may want to have cubes which are only adding a service,
  no persistent data (eg embedding for instance)


Standard library
````````````````

A library of standard cubes are available from `CubicWeb Forge`_
Cubes provide entities and views.

The available application entities are:

* addressbook_: PhoneNumber and PostalAddress

* basket_: Basket (like a shopping cart)

* blog_: Blog (a *very* basic blog)

* comment_: Comment (to attach comment threads to entities)

* event_: Event (define events, display them in calendars)

* file_: File (to allow users to upload and store binary or text files)

* folder_: Folder (to organize things but grouping them in folders)

* keyword_: Keyword (to define classification schemes)

* link_: Link (to collect links to web resources)

* mailinglist_: MailingList (to reference a mailing-list and the URLs
  for its archives and its admin interface)

* person_: Person (easily mixed with addressbook)

* tag_: Tag (to tag anything)

* task_: Task (something to be done between start and stop date)

* zone_: Zone (to define places within larger places, for example a
  city in a state in a country)

.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
.. _basket: http://www.cubicweb.org/project/cubicweb-basket
.. _blog: http://www.cubicweb.org/project/cubicweb-blog
.. _comment: http://www.cubicweb.org/project/cubicweb-comment
.. _event: http://www.cubicweb.org/project/cubicweb-event
.. _file: http://www.cubicweb.org/project/cubicweb-file
.. _folder: http://www.cubicweb.org/project/cubicweb-folder
.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
.. _link: http://www.cubicweb.org/project/cubicweb-link
.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
.. _person: http://www.cubicweb.org/project/cubicweb-person
.. _tag: http://www.cubicweb.org/project/cubicweb-tag
.. _task: http://www.cubicweb.org/project/cubicweb-task
.. _zone: http://www.cubicweb.org/project/cubicweb-zone