doc/devmanual_fr/chap_fondements_cubicweb.txt
changeset 22 50f20cf0f440
parent 20 dfddcbef6684
child 36 f6bcad5c6dfe
equal deleted inserted replaced
21:09cad2ba7bc7 22:50f20cf0f440
    96   Java's RMI (Remote Method Invocation), pouvant être utilisé pour la
    96   Java's RMI (Remote Method Invocation), pouvant être utilisé pour la
    97   communication entre la partie web du framework et l'entrepôt RQL.
    97   communication entre la partie web du framework et l'entrepôt RQL.
    98 
    98 
    99 .. _`Python Remote Object`: http://pyro.sourceforge.net/
    99 .. _`Python Remote Object`: http://pyro.sourceforge.net/
   100 .. _`yams`: http://www.logilab.org/project/name/yams/
   100 .. _`yams`: http://www.logilab.org/project/name/yams/
       
   101 
       
   102 
       
   103 Moteur `CubicWeb`
       
   104 -----------------
       
   105 Le moteur web de cubicweb consiste en quelques classes gérant un ensemble d'objets
       
   106 chargés dynamiquement au lancement de cubicweb. Ce sont ces objets dynamiques, issus
       
   107 du modèle ou de la librairie, qui construisent le site web final. Les différents
       
   108 composants dynamiques sont par exemple : 
       
   109 
       
   110 * coté client et serveur
       
   111 
       
   112  - les définitions d'entités, contenant la logique permettant la manipulation des
       
   113    données de l'application
       
   114 
       
   115 * coté client
       
   116 
       
   117   - les *vues* , ou encore plus spécifiquement 
       
   118 
       
   119     - les boites
       
   120     - l'en-tête et le pied de page
       
   121     - les formulaires
       
   122     - les gabarits de pages
       
   123 
       
   124   - les *actions*
       
   125   - les *controleurs*
       
   126 
       
   127 * coté serveur
       
   128 
       
   129   - les crochets de notification
       
   130   - les vues de notification
       
   131 
       
   132 Les différents composants du moteur sont :
       
   133 
       
   134 * un frontal web (seul twisted disponible pour le moment), transparent du point
       
   135   de vue des objets dynamiques
       
   136 * un objet encapsulant la configuration
       
   137 * un `vregistry` (`cubicweb.cwvreg`) contenant les objets chargés dynamiquements
       
   138 
       
   139 Détail de la procédure d'enregistrement
       
   140 ---------------------------------------
       
   141 Au démarage le `vregistry` ou base de registres inspecte un certain nombre de
       
   142 répertoires à la recherche de définition de classes "compatible". Après une
       
   143 procédure d'enregistrement les objets sont affectés dans différents registres
       
   144 afin d'être ensuite séléctionné dynamiquement pendant le fonctionnement de
       
   145 l'application.
       
   146 
       
   147 La classe de base de tout ces objets est la classe `AppRsetObject` (module
       
   148 `cubicweb.common.appobject`). 
       
   149 
       
   150 
       
   151 API Python/RQL
       
   152 --------------
       
   153 
       
   154 Inspiré de la db-api standard, avec un object Connection possédant les méthodes
       
   155 cursor, rollback et commit principalement. La méthode importante est la méthode
       
   156 `execute` du curseur :
       
   157 
       
   158 `execute(rqlstring, args=None, eid_key=None, build_descr=True)`
       
   159 
       
   160 :rqlstring: la requête rql à éxécuter (unicode)
       
   161 :args: si la requête contient des substitutions, un dictionnaire contenant les
       
   162        valeurs à utiliser
       
   163 :eid_key: 
       
   164    un détail d'implémentation du cache de requêtes RQL fait que si une substitution est
       
   165    utilisée pour introduire un eid *levant des ambiguités dans la résolution de
       
   166    type de la requête*, il faut spécifier par cet argument la clé correspondante
       
   167    dans le dictionnaire
       
   168 
       
   169 C'est l'objet Connection qui possède les méthodes classiques `commit` et
       
   170 `rollback`. Vous ne *devriez jamais avoir à les utiliser* lors du développement
       
   171 d'interface web sur la base du framework CubicWeb étant donné que la fin de la
       
   172 transaction est déterminée par celui-ci en fonction du succès d'éxécution de la
       
   173 requête. 
       
   174 
       
   175 NOTE : lors de l'éxécution de requêtes de modification (SET,INSERT,DELETE), si une
       
   176 requête génère une erreur liée à la sécurité, un rollback est systématiquement
       
   177 effectuée sur la transaction courante.
       
   178 
       
   179 
       
   180 La classe `Request` (`cubicweb.web`)
       
   181 ------------------------------------
       
   182 Une instance de requête est créée lorsque une requête HTTP est transmise au
       
   183 serveur web. Elle contient des informations telles que les paramètres de
       
   184 formulaires, l'utilisateur connecté, etc. 
       
   185 
       
   186 **De manière plus générale une requête représente une demande d'un utilisateur,
       
   187 que se soit par HTTP ou non (on parle également de requête rql coté serveur par
       
   188 exemple)**
       
   189 
       
   190 Une instance de la classe `Request` possède les attributs :
       
   191 
       
   192 * `user`, instance de`cubicweb.common.utils.User` correspondant à l'utilisateur
       
   193   connecté 
       
   194 * `form`, dictionaire contenant les valeurs de formulaire web
       
   195 * `encoding`, l'encodage de caractère à utiliser dans la réponse
       
   196 
       
   197 Mais encore :
       
   198 
       
   199 :Gestion des données de session:        
       
   200   * `session_data()`, retourne un dictionaire contenant l'intégralité des
       
   201     données de la session
       
   202   * `get_session_data(key, default=None)`, retourne la valeur associée à
       
   203     la clé ou la valeur `default` si la clé n'est pas définie
       
   204   * `set_session_data(key, value)`, associe une valeur à une clé
       
   205   * `del_session_data(key)`,  supprime la valeur associé à une clé
       
   206     
       
   207 
       
   208 :Gestion de cookie:
       
   209   * `get_cookie()`, retourne un dictionnaire contenant la valeur de l'entête
       
   210     HTTP 'Cookie'
       
   211   * `set_cookie(cookie, key, maxage=300)`, ajoute un en-tête HTTP `Set-Cookie`,
       
   212     avec une durée de vie 5 minutes par défault (`maxage` = None donne un cooke
       
   213     *de session"* expirant quand l'utilisateur ferme son navigateur
       
   214   * `remove_cookie(cookie, key)`, fait expirer une valeur
       
   215 
       
   216 :Gestion d'URL:
       
   217   * `url()`, retourne l'url complète de la requête HTTP
       
   218   * `base_url()`, retourne l'url de la racine de l'application
       
   219   * `relative_path()`, retourne chemin relatif de la requête
       
   220 
       
   221 :Et encore...:
       
   222   * `set_content_type(content_type, filename=None)`, place l'en-tête HTTP
       
   223     'Content-Type'
       
   224   * `get_header(header)`, retourne la valeur associé à un en-tête HTTP
       
   225     arbitraire de la requête
       
   226   * `set_header(header, value)`, ajoute un en-tête HTTP arbitraire dans la
       
   227     réponse 
       
   228   * `cursor()` retourne un curseur RQL sur la session
       
   229   * `execute(*args, **kwargs)`, raccourci vers .cursor().execute()
       
   230   * `property_value(key)`, gestion des propriétés (`EProperty`)
       
   231   * le dictionaire `data` pour stocker des données pour partager de
       
   232     l'information entre les composants *durant l'éxécution de la requête*.
       
   233 
       
   234 A noter que cette classe est en réalité abstraite et qu'une implémentation
       
   235 concrète sera fournie par le *frontend* web utilisé (en l'occurent *twisted*
       
   236 aujourd'hui). Enfin pour les vues ou autres qui sont éxécutés coté serveur,
       
   237 la majeure partie de l'interface de `Request` est définie sur la session
       
   238 associée au client. 
       
   239 
       
   240 
       
   241 La classe `AppObject`
       
   242 ---------------------
       
   243 
       
   244 En général :
       
   245 
       
   246 * on n'hérite pas directement des cette classe mais plutôt d'une classe
       
   247   plus spécifique comme par exemple `AnyEntity`, `EntityView`, `AnyRsetView`,
       
   248   `Action`...
       
   249 
       
   250 * pour être enregistrable, un classe fille doit définir son registre (attribut
       
   251   `__registry__`) et son identifiant (attribut `id`). Généralement on n'a pas à
       
   252   s'occuper du registre, uniquement de l'identifiant `id` :) 
       
   253 
       
   254 On trouve un certain nombre d'attributs et de méthodes définis dans cette classe
       
   255 et donc commune à tous les objets de l'application :
       
   256 
       
   257 A l'enregistrement, les attributs suivants sont ajoutés dynamiquement aux
       
   258 *classes* filles:
       
   259 
       
   260 * `vreg`, le `vregistry` de l'application
       
   261 * `schema`, le schéma de l'application
       
   262 * `config`, la configuration de l'application
       
   263 
       
   264 On trouve également sur les instances les attributs :
       
   265 
       
   266 * `req`, instance de `Request`
       
   267 * `rset`, le "result set" associé à l'objet le cas échéant
       
   268 * `cursor`, curseur rql sur la session
       
   269 
       
   270 
       
   271 :Gestion d'URL:
       
   272   * `build_url(method=None, **kwargs)`, retourne une URL absolue construites à
       
   273     partir des arguments donnés. Le *controleur* devant gérer la réponse
       
   274     peut-être spécifié via l'argument spécial `method` (le branchement est
       
   275     théoriquement bien effectué automatiquement :).
       
   276 
       
   277   * `datadir_url()`, retourne l'url du répertoire de données de l'application
       
   278     (contenant les fichiers statiques tels que les images, css, js...)
       
   279 
       
   280   * `base_url()`, raccourci sur `req.base_url()`
       
   281 
       
   282   * `url_quote(value)`, version *unicode safe* de de la fonction `urllib.quote`
       
   283 
       
   284 :Manipulation de données:
       
   285 
       
   286   * `etype_rset(etype, size=1)`, raccourci vers `vreg.etype_rset()`
       
   287 
       
   288   * `eid_rset(eid, rql=None, descr=True)`, retourne un objet result set pour
       
   289     l'eid donné
       
   290   * `entity(row, col=0)`, retourne l'entité correspondant à la position données
       
   291     du "result set" associé à l'objet
       
   292 
       
   293   * `complete_entity(row, col=0, skip_bytes=True)`, équivalent à `entity` mais
       
   294     appelle également la méthode `complete()` sur l'entité avant de la retourner
       
   295 
       
   296 :Formattage de données:
       
   297   * `format_date(date, date_format=None, time=False)`
       
   298   * `format_time(time)`,
       
   299 
       
   300 :Et encore...:
       
   301 
       
   302   * `external_resource(rid, default=_MARKER)`, accède à une valeur définie dans
       
   303     le fichier de configuration `external_resource`
       
   304     
       
   305   * `tal_render(template, variables)`, 
       
   306 
       
   307 
       
   308 **NOTE IMPORTANTE**
       
   309 Lorsqu'on hérite d'`AppObject` (même indirectement), il faut **toujours**
       
   310 utiliser **super()** pour récupérer les méthodes et attributs des classes
       
   311 parentes, et pas passer par l'identifiant de classe parente directement.
       
   312 (sous peine de tomber sur des bugs bizarres lors du rechargement automatique
       
   313 des vues). Par exemple, plutôt que d'écrire::
       
   314 
       
   315       class Truc(PrimaryView):
       
   316           def f(self, arg1):
       
   317               PrimaryView.f(self, arg1)
       
   318 
       
   319 Il faut écrire::
       
   320       
       
   321       class Truc(PrimaryView):
       
   322           def f(self, arg1):
       
   323               super(Truc, self).f(arg1)
       
   324 
       
   325 
       
   326 
       
   327 
   101 
   328 
   102 
   329 
   103 Structure standard d'un cube
   330 Structure standard d'un cube
   104 ----------------------------
   331 ----------------------------
   105 
   332