Justification

Les CommonDBRelation et CommonDBChild sont communs à un certain nombre de classes. On peut ainsi centraliser dedans certaines méthodes.

Souvent, un "enfant" ne peut être créé que si on a les mêmes droits sur l'élément auquel on l'attache. Par exemple, on ne peut attacher un port réseau à un équipement que si l'on a accès en écriture à cet élément.
C'est pourquoi on centralise des codes de gestion des droits (canCreate, canView, canCreateItem ...).
Le second champ d'application de la centralisation est la gestion de la mise à jours de l'historique.

Terminologie

  • On appel l'élément fils (ou fils) l'objet qui hérite de la classe CommonDBRelation ou de CommonDBChild ;
  • On appel l'élément père (ou père) l'objet sur lequel s'appuie l'élément fils. On notera qu'un fils de type CommonDBChild possède un père alors qu'un fils CommonDBRelation en possède deux ;
  • On appel cohérence d'entitée le fait que deux éléments peuvent être reliés (un CommonDBChild et son Item, deux père entre eux par un CommonDBRelation ...) car dans des entitées compatibles (mêmes entitées ou l'une est l'entitée ancêtre de l'autre avec une recursivité) ;
  • On appel un fils sans père, un CommonDBChild ou un CommonDBRelation de le père ou l'un des pères ne pointe sur aucun item (ie. : $itemtype? = NULL et/ou $items_id? = 0) Cela pourrait être le cas d'un composant dans le stock, non affecté à un Item.

Méta-centralisation

Ces deux classes reposent sur des items définis par <itemtype?, items_id?> (un item pour CommonDBChild, deux items pour CommonDBRelation) qui fonctionnent de la même manière ($itemtype = _nom de classe_ ou itemtype pour un type dynamique).
Donc, il est logique de mettre en commun certains bouts de code.
La nouvelle classe CommonDBConnexity centralise ce code (les deux autres classes en héritent).

Gestion des droits

Les droits sur un fils (création, visualisation, destruction, mise à jour) par rapport au(x) père(s) sont de trois natures différentes :
  • le fils peut être manipulé quelque soit le droit que l'on a sur le père ou lorsque l'on ne souhaite pas faire de tests des droits du père : DONT_CHECK_ITEM_RIGHTS
  • le fils peut être manipulé uniquement si on a le droit de voir le père (exemple : on peut utiliser un DropDown sans avoir le droit de le créer) : HAVE_VIEW_RIGHT_ON_ITEM ;
  • le fils ne peut être manipulé que si on a le même droit sur le père (on ne peut modifier un fils que si on peut modifier son père) : HAVE_VIEW_RIGHT_ON_ITEM ;

Nota : pour un CommonDBRelation les droits vis-à-vis d'un des deux père peut être différent de ceux pour l'autre père.

Amélioration pour les fils sans père

On peut envisager d'ajouter un masque (CAN_BE_FREE) en plus de ces trois paramètres pour permettre la création de fils sans père.

En effet, pour le moment, par défaut, les canCreateItem, canViewItem ... reposent sur la possibilité de lire les droits sur le père.
Donc, si on ne peut charger le père (le cas lorsque le fils est sans père), le CommonDBConnexity renvoie qu'il est impossible de créer, modifier, voir ou supprimer le fils. Donc, l'opération est interdite.

Nota : dans ce cas, il faut également prévoir un mécanisme pour s'assurer de la cohérence d'entitée entre le fils et son ou ses pères.

Gestion de l'historique

L'historique est géré automatiquement par les classes CommonDBRelation et CommonDBChild : on notifie automatiquement l'historique du père pour signaler l'ajout, la modification ou la destruction d'un fils.

Le CommonDBChild n'est pas paramétrable : quoiqu'il arrive le père est notifié (cf. la section "Limitation" ci-dessous).

Pour le CommonDBRelation, deux paremètres booléens permettent de le configurer :
  • $logs_for_itemtype_1 précise s'il faut le notifier le premier père lorsque la relation est modifiée ;
  • $logs_for_itemtype_2 précise s'il faut le notifier le second père lorsque la relation est modifiée ;

Limitation

Cette gestion automatique de l'historique repose sur la surcharge des méthodes post_addItem, post_updateItem et post_deleteFromDB.
Si la classe héritée surcharge ces méthodes sans faire appel à ces méthodes par appel à parent::post_*, alors on perd ce comportement.
C'est à la fois un problème et une bonne chose :
  • c'est un problème car beaucoup de classes héritées utilisent leur propres mécanisme de gestion de l'historique qui peut être imparfait ou lacunaire. Ainsi, elless perdent le bénéfice de cette factorisation. Un travail de recensement serait utile à ce niveau (cf. #3828) ;
  • c'est un bénéfice car pour certains cas, on peut souhaiter avoir un traitement spécifique de l'historique indépendant de ce mécanisme commun. La surcharge de ces méthode permet de passer outre.

Amélioration

On peut réfléchir, avec cette centralisation, à gérer les historiques en cascade : lorsqu'on notifie l'historique du père, si ce dernier est lui-même un CommonDBRelation ou un CommonDBChild, on peut notifier l'historiques des pères de ce père. Cela permet de propager la notification jusqu'aux éléments principaux (ordinateur, imprimante, switch ...).

Traitements spécifiques et compatibilité avec les versions antérieures

On ne peut faire abstraction de ce qui existait jusque là (cf. version 0.83.x).

CommonDBRelation

Les méthod canCreate, canCreateItem, canView ... de CommonDBRelation ont été surchargées.
La seule solution pour désactiver ces mécanismes de contrôle des droits est de paramétrer correctement $checkItem_1_Rights et $checkItem_2_Rights.

cohérence d'entité

En plus des tests unitaires sur chaque père (paramétrés par $checkItem_1_Rights et $checkItem_2_Rights), on paramètre la cohérence d'entité avec un troisième paramètre $check_entity_coherency.

compatibilité de contrôle des droits

Jusque là, les tests des droits sur le CommonDBRelation étaient gérés par la surcharge de la méthode can. Cela est contraire à la philosophie introduite par #3806.
Par défaut, les droits étaient gérés par les attributs $check_entities et $checks_only_for_itemtype1.
Pour garantir la compatibilité, il faut suivre les règles suivantes :

   $check_entity_coherency = $check_entities;
   $checkItem_1_Rights  = self::HAVE_SAME_RIGHT_ON_ITEM;
   $checkItem_2_Rights  = ($checks_only_for_itemtype1 ? self::DONT_CHECK_ITEM_RIGHTS : self::HAVE_SAME_RIGHT_ON_ITEM);

compatibilité de gestion de l'historique

Dans la version précédente de GLPI, la gestion de l'historique du CommonDBRelation était limitée à l'ajout et à la suppression. De plus, on pouvait désactiver le log sur le père 2 avec l'attribut $logs_only_for_itemtype1.
La nouvelle version est plus avancée car elle permet de gérer indépendamment le log pour chacun des pères. De plus, on peut logger la mise à jour d'un CommonDBRelation. Cela est utile lorsque la relation comporte quelques champs supplémentaire (cf. Item_Device?).
Pour garantir la compatibilité, il faut suivre les règles suivantes :

   $logs_for_itemtype_1 = true;
   $logs_for_itemtype_2 = ($logs_only_for_itemtype1 == false);

CommonDBChild

Précédemment, aucun test sur les droits n'étaient réalisés par les CommonDBChild. Il en résulte une grande anarchie. C'est pourquoi les méthodes canCreate, canUpdate, canCreateItem ... n'ont pas été surchargées dans CommonDBChild.
Il revient donc, à chaque classe héritée, de les surcharger. Par exemple, pour la création (canCreate et canCreateItem), on peut surcharger comme cela :

   static function canCreate() {
      return (Session::haveRight('networking','w') // check specific right for this class
              && parent::canChild('canCreate'));
   }

   function canCreateItem() {
      return parent::canChildItem('canCreateItem', 'canCreate');
   }

On notera, que dans le cas du canCreateItem on n'a plus besoin de tester les droits spécifiques de la classe car ils sont déjà testés par canCreate.