Base de données

Une discussion solide sur le design du modèle de données de Elgg et ses motivations.

Aperçu

Dans Elgg, tout fonctionne sur un modèle de données unifié construit sur des unités atomiques de données appelées entités.

Il est recommandé que les plugins n’interagissent pas directement avec la base de données, afin de créer un système plus stable et une meilleure expérience utilisateur parce que les contenus créés par différents plugins peuvent être mélangés ensemble de manière cohérente. Avec cette approche, les plugins sont plus rapides à développer, et sont en même temps plus puissants.

Chaque entité dans le système hérite de la classe ElggEntity. Cette classe contrôle les permissions d’accès, la propriété, le conteneur, et fournit une API cohérente pour accéder aux propriétés des entités et les modifier.

Vous pouvez étendre les entités avec des informations supplémentaires de deux manières :

Metadata : Ces informations décrivent l’entité, elles sont habituellement

ajoutées par l’auteur de l’entité quand l’entité est créée ou modifiée. Des exemples de métadonnées incluent les tags, un numéro ISBN ou un ID tierce-partie, une adresse, des coordonnées géographiques, etc. Imaginez les métadonnées comme un simple système de stockage clef-valeur.

Annotations : Ces informations étendent l’entité avec des propriétés, habituellement

ajoutées par une tierce-partie. De telles propriétés comprennent par exemple les notations, les likes ou les votes.

Les principales différences entre métadonnées et annotations :

  • les métadonnées n’ont pas de propriétaire, alors que les annotations en ont

  • les métadonnées ne disposent pas de contrôle d’accès, alors que les annotations en disposent

  • les métadonnées sont préchargées lorsque l’entité est construite, alors que les annotations ne sont chargées que sur demande

Ces différences peuvent avoir des implications sur les performances et votre logique applicative, aussi considérez avec soin la manière dont vous souhaiter attacher des données à vos entités.

In certain cases, it may be beneficial to avoid using metadata and annotations and create new entities instead and attaching them via container_guid or a relationship.

Modèle de données

Le diagramme du modèle de données de Elgg

Le diagramme du modèle de données de Elgg

Entités

ElggEntity est la classe de base pour le modèle de données de Elgg et supporte un jeu de propriétés et de méthodes communes.

  • A numeric Globally Unique IDentifier (See GUIDs)

  • Access permissions. (When a plugin requests data, it never gets to touch data that the current user doesn’t have permission to see)

  • An arbitrary subtype (more below)

  • Un propriétaire

  • A container, used to associate content with a group or a user

  • UNIX timestamps for certain actions:
    • When was the entity created

    • When was the entity last updated

    • When did the the entity perform it’s last action, or was acted upon

    • When was the entity deleted

  • A deleted state (deleted entities aren’t shown in normal circumstances)

  • A disabled state (disabled entities aren’t shown in normal circumstances)

Types

Actual entities will be instances of four different subclasses, each having a distinct type property and their own additional properties and methods.

Type

Classe PHP

Représente

object

ElggObject

Les plupart des contenus créés par les utilisateurs, tels que des articles de blog, des chargements de fichiers, et des signets.

group

ElggGroup

Un groupe organisé d’utilisateurs avec sa propre page de profil

user

ElggUser

Un utilisateur du système

site

ElggSite

Le site servi par l’installation Elgg

Chaque type a sa propre API étendue. Par ex. les utilisateurs peuvent être en contact avec d’autres utilisateurs, un groupe peut avoir des membres, tandis que les objets peuvent être aimés et commentés.

Sous-types « subtypes »

Chaque entité doit définir un sous-type subtype, que les plugins utilisent pour spécialiser encore l’entité. Elgg facilite le fait de rechercher des entités spécifiques d’un sous-type donné (ou de plusieurs), ainsi que de leur assigner des comportements et vues spéciales.

Les sous-types sont communément donnés aux instances de ElggEntity pour définir le type de contenu créé. Par ex. le plugin blog crée des objets avec le sous-type "blog".

Par défaut, les utilisateurs, les groupes et les sites ont respectivement les sous-types user, group et site.

Plugins can use custom entity classes that extend the base type class. To do so, they need to register their class at runtime (e.g. in the 'init', 'system' handler), using elgg_set_entity_class(). For example, the blog plugin could use elgg_set_entity_class('object', 'blog', \ElggBlog::class).

Les plugins peuvent utiliser elgg-plugin.php pour définir une classe d’entité via le paramètre raccourci entities.

Trucs à savoir sur les sous-types

Avant que la méthode save() d’une entité soit appelée, le sous-type doit être défini en écrivant une chaîne de caractère dans la propriété subtype.

Avertissement

Subtype cannot be changed after saving.

GUIDs

Un GUID est un entier qui définit de manière unique chaque entité dans une installation Elgg (un IDentifiant Global Unique - Globally Unique IDentifier). Il est assigné automatiquement la première fois qu’une entité est enregistré, et ne peut jamais être changé.

Certaines fonctions de l’API de Elgg fonctionnent avec des GUIDs au lieu d’objets ElggEntity.

Deleted state

As of Elgg 6.0 entities also have a deleted state. When a given entity type/subtype supports it before it’s removed from the database it can get the deleted state. This way a user can restore the entity if the delete action was done too hastily. For example the user removes a blog post, but this shouldn’t have been done. Now the user has the option to restore the blog in it’s original state without having to rewrite it.

In the database this is managed by the deleted column in the entities table which can have a value of yes or no (default) and by the time_deleted column which holds a UNIX timestamp when the entity was deleted.

A site administrator can set a retention period for deleted items. Once the retention period is passed the entity will be permanently removed from the database.

Deleted items will not show in normal use cases. In the example of the blog post, the blog will not show up in the blog listing and if anyone has saved a link to the blog post the page will return a 404 - Not Found error.

There is a special page in the user settings section where all the deleted entities of the user can be viewed. Here the user has the option to restore the entity or permanently delete it before the retention period has passed.

This special page is also available to group owners for deleted entities in their group.

Voir aussi

For more information check out the Restore capability documentation

ElggObject

The ElggObject entity type represents arbitrary content within an Elgg installation things like blog posts, uploaded files, etc.

Beyond the standard ElggEntity properties, ElggObject also supports:

  • title Le titre de l’objet (texte sans HTML)

  • description Une description de l’objet (HTML)

La plupart des autrse données à propos de l’objet sont généralement stockées via des métadonnées.

ElggUser

The ElggUser entity type represents users within an Elgg installation. These will be set to disabled until their accounts have been activated (unless they were created from within the admin panel).

Beyond the standard ElggEntity properties, ElggUser also supports:

  • name Le nom de l’utilisateur en texte brut. Par ex. « Hugh Jackman »

  • username Leur identifiant. Par ex. « hjackman »

  • password Une version hachée de leur mot de passe

  • email Leur adresse e-mail

  • language Leur code de langue par défaut.

  • prev_last_action La précédente valeur de last_action

  • last_login Le timestamp UNIX de leur dernière connexion

  • prev_last_login la précédente valeur de last_login

ElggSite

Le type d’entité ElggSite représente votre installation Elgg (via l’URL de votre site).

Beyond the standard ElggEntity properties, ElggSite also supports:

  • name Le nom du site

  • description Une description du site

  • url L’adresse du site

ElggGroup

Le type d’entité ElggGroup représente une association d’utilisateurs Elgg. Les utilisateurs peuvent rejoindre, quitter les groupes, et y publier du contenu.

Beyond the standard ElggEntity properties, ElggGroup also supports:

  • name Le nom du groupe (texte sans HTML)

  • description Une description du groupe (HTML)

ElggGroup a des méthodes additionnelles pour gérer le contenu et les adhésions.

Le plugin Groups

Not to be confused with the entity type ElggGroup, Elgg comes with a plugin called « Groups » that provides a default UI/UX for site users to interact with groups. Each group is given a profile page linking users to content within the group.

Vous pouvez modifier l’expérience utilisateur via les moyens traditionnels d’extension de plugin, ou remplacer complètement le plugin Groups par votre propre plugin.

Several of the Elgg core plugins offer support for group content like blogs, bookmarks, discussions, files and pages.

Écrire un plugin compatibles avec les groupes

Les développeurs de plugins ne devraient pas trop s’inquiéter de l’écriture de fonctionnalités compatibles avec les groupes, mais il y a quelques points clefs :

Ajouter du contenu

En passant le groupe en tant que container_guid via un champ de saisie caché, vous pouvez utiliser un seul formulaire et une seule action pour ajouter du contenu à la fois pour un utilisateur ou pour un groupe.

Utilisez ElggEntity->canWriteToContainer(0, $type, $subtype) pour déterminer si l’utilisateur actuel a le droit d’ajouter du contenu à un groupe.

Soyez attentif au fait que vous allez devoir passer le GUID du conteneur ou l’identifiant à la page responsable de la publication, et la valeur associée, de sorte que ceci puisse être ensuite conservé dans votre formulaire sous forme de champ de saisie caché, pour un passage plus aisé vers vos actions. Au sein d’une action « create », vous allez avoir besoin de récupérer ce champ de saisie et de l’enregistrer sous forme de propriété de votre nouvel élément (la valeur par défaut est le conteneur actuel de l’utilisateur) :

$user = elgg_get_logged_in_user_entity();
$container_guid = (int) get_input('container_guid');

if ($container_guid) {
    $container = get_entity($container_guid);

    if (!$container instanceof \ElggEntity || !$container->canWriteToContainer($user->guid, 'object', 'my_content_subtype')) {
        return elgg_error_response(elgg_echo('actionunauthorized'));
    }
} else {
    $container_guid = elgg_get_logged_in_user_guid();
}

$object = new ElggObject();
$object->container_guid = $container_guid;

...

// redirect to the created object
return elgg_ok_response('', $object->getURL());

Propriété

Les entités ont une propriété GUID owner_guid, qui définit son propriétaire. Typiquement ceci renvoie au GUID d’un utilisateur, quoique les sites et les utilisateurs eux-même n’ont souvent pas de propriétaire (valeur de 0).

La propriété d’une entité détermine, d’une part, si vous pouvez ou non accéder à cette entité, ou la modifier.

Conteneurs « containers »

In order to easily search content by group or by user, content is generally set to be « contained » by either the user who posted it, or the group to which the user posted. This means the new object’s container_guid property will be set to the GUID of the current ElggUser or the target ElggGroup.

Par ex., trois articles de blog peuvent avoir des propriétaires différentes, mais être tous contenus dans le groupe où ils ont été publiés.

Note

This is not always true. Comment entities are contained by the object commented upon, and in some 3rd party plugins the container may be used to model a parent-child relationship between entities (e.g. a « folder » object containing a file object).

Annotations

Les annotations sont des éléments de données attachées à une entité qui permet aux utilisateurs de laisser des évaluations, ou d’autres types de réactions pertinentes. Un plugin de sondage pourrait enregistrer des votes sous forme d’annotations.

Les annotations sont stockées sous formes d’instances de la classe ElggAnnotation.

Chaque annotation dispose de :

  • Un type d’annotation interne (tel que comment)

  • A value (which can be a string, a boolean or an integer)

  • Un niveau d’accès distinct de celui de l’entité à laquelle elle est attachée

  • Un propriétaire

Ajouter une annotation

La manière la plus simple d’ajouter une annotation est d’utiliser la méthode annotate sur une entité, qui est définie comme :

public function annotate(
    $name,           // The name of the annotation type (eg 'comment')
    $value,          // The value of the annotation
    $access_id = 0,  // The access level of the annotation
    $owner_id = 0,   // The annotation owner, defaults to current user
    $vartype = ""    // 'text', 'bool' or 'integer'
)

Par exemple, pour donner une notation à une entité, vous pouvez appeler :

$entity->annotate('rating', $rating_value, $entity->access_id);

Lire des annotations

Pour récupérer les annotations d’une entité, vous pouvez appeler la méthode suivante :

$annotations = $entity->getAnnotations(
    $name,    // The type of annotation
    $limit,   // The number to return
    $offset,  // Any indexing offset
    $order,   // 'asc' or 'desc' (default 'asc')
);

Si votre type d’annotation utilise largement des valeurs entières, plusieurs fonctions mathématiques utiles sont fournies :

$averagevalue = $entity->getAnnotationsAvg($name);  // Get the average value
$total = $entity->getAnnotationsSum($name);         // Get the total value
$minvalue = $entity->getAnnotationsMin($name);      // Get the minimum value
$maxvalue = $entity->getAnnotationsMax($name);      // Get the maximum value

Fonctions d’assistance utiles

Commentaires

Si vous souhaitez fournir une fonctionnalité de commentaire sur les objets de votre plugin, la fonction suivante va fournir le listing complet, le formulaire et les actions :

function elgg_view_comments(ElggEntity $entity)

Métadonnées

Metadata in Elgg allows you to store extra data on an ElggEntity beyond the built-in fields that entity supports. For example, ElggObjects only support the basic entity fields plus title and description, but you might want to include tags or an ISBN number. Similarly, you might want users to be able to save a date of birth.

Sous le capot, les métadonnées sont stockées sous forme d’instance de la classe ElggMetadata, mais vous n’avez pas à vous soucier de cela en pratique (quoique si vous êtes intéressé, voyez la référence de la classe ElggMetadata). Ce que vous avez besoin de savoir :

  • Vous pouvez potentiellement avoir plusieurs éléments de chaque type de métadonnée attachés à la même entité

  • Comme les annotations, les valeurs sont stockées sous forme de chaînes de caractères, de booléens ou d’entiers

  • The metadata name is case sensitive

Le cas simple

Ajouter des métadonnées

Pour ajouter une métadonnée à une entité, appelez simplement :

$entity->metadata_name = $metadata_value;

Par exemple, pour ajouter une date d’anniversaire à un utilisateur :

$user->dob = $dob_timestamp;

Ou pour ajouter des tags à un objet :

$object->tags = array('tag one', 'tag two', 'tag three');

Lorsque vous ajoutez une métadonnée de cette manière :

  • Réassigner une métadonnée va remplacer l’ancienne valeur

This is suitable for most purposes. Be careful to note which attributes are metadata and which are built in to the entity type that you are working with. You do not need to save an entity after adding or updating metadata. You do need to save an entity if you have changed one of its built in attributes. As an example, if you changed the access_id of an ElggObject, you need to save it or the change isn’t pushed to the database.

Lire des métadonnées

Pour récupérer une métadonnée, traitez-la comme une propriété d’une entité :

$tags_value = $object->tags;

Note that this will return the absolute value of the metadata. To get metadata as an ElggMetadata object, you will need to use the methods described in the finer control section below.

If you stored multiple values in this piece of metadata (as in the « tags » example above), you will get an array of all those values back. If you stored only one value, you will get a string, boolean or integer back. Storing an array with only one value will return a string back to you. E.g.

$object->tags = array('tag');
$tags = $object->tags;
// $tags will be the string "tag", NOT array('tag')

Pour récupérer toujours un tableau, castez simplement vers un tableau ;

$tags = (array)$object->tags;

Lire des métadonnées comme des objets

elgg_get_metadata is the best function for retrieving metadata as ElggMetadata objects:

Par ex., pour récupérer la date de naissance d’un utilisateur

elgg_get_metadata([
    'metadata_name' => 'dob',
    'guid' => $user_guid,
]);

Ou pour récupérer tous les objets de métadonnées :

elgg_get_metadata([
    'guid' => $user_guid,
    'limit' => false,
]);

Note

When retrieving metadata by name the names are matched case-insensitive. Keep your code clean and do not mix uppercase and lowercase metadata names.

Erreurs courantes

« Ajouter » des métadonnées à la suite

Notez que vous ne pouvez pas « ajouter » des valeurs aux tableaux de métadonnées comme si c’étaient des tableaux php normaux. Par exemple, le code suivant ne fera pas ce qu’il semblerait qu’il devrait faire.

$object->tags[] = "tag four";

Essayer de stocker des tableaux indexés

Elgg ne supporte pas le stockage de tableaux indexés (paires clef/valeur) dans les métadonnées. Par exemple, le code suivant ne fonctionne pas comme vous pourriez le penser de prime abord :

// Won't work!! Only the array values are stored
$object->tags = array('one' => 'a', 'two' => 'b', 'three' => 'c');

Au lieu de cela, vous pouvez conserver cette information de cette manière :

$object->one = 'a';
$object->two = 'b';
$object->three = 'c';

Conserver des GUIDs dans des métadonnées

Quoiqu’il existe certains cas pour stocker les GUIDs d’entités dans des métadonnées, les relations Relationships sont une construction bien plus adaptée pour relier les entités les unes aux autres.

Relations

Les relations vous permettent d’associer des entités ensemble. Exemples : un artiste a des fans, un utilisateur est membre d’une organisation, etc.

La classe ElggRelationship modélise une relation directe entre deux entités, en faisant la déclaration :

« {sujet} est un {nom} de {cible}. »

Nom de l’API

Modèles

Représente

guid_one

Le sujet

Quelle entité est reliée

relationship

Le nom

Le type de relation

guid_two

La cible

L’entité à laquelle le sujet est relié

Le type de relation peut également être un verbe, faisant la déclaration :

« {sujet} {verbe} {cible}. »

Par ex. Utilisateur A aime « likes » l’article de blog B

Chaque relation a une direction. Imaginez un archer qui tire une flèche vers une cible ; la flèche se déplace dans une direction, en reliant le sujet (l’archer) à la cible.

Une relation n’implique pas de réciprocité. A suit B n’implique pas que B suive A.

Relationships do not have access control. They’re never hidden from view and can be edited with code at any privilege level, with the caveat that the entities in a relationship may be invisible due to access control!

Travailler avec des relations

Créer une relation

Par exemple pour établir que l’utilisateur « $user est un fan de l’artiste $artist » (l’utilisateur est le sujet, l’artiste est la cible):

$success = $user->addRelationship($artist->guid, 'fan');

Ceci déclenche l’événement [create, relationship], en lui passant l’objet ElggRelationship créé. Si un gestionnaire retourne false, la relation ne sera pas créée et $success vaudra false.

Vérifier une relation

Par exemple pour vérifier que l’utilisateur « $user est un fan de l’artiste $artist »:

if ($user->hasRelationship($artist->guid, 'fan')) {
    // relationship exists
}

Supprimer une relation

Par exemple pour pouvoir affirmer que l’utilisateur « $user n’est désormais plus un fan de l’artiste $artist »:

$was_removed = $user->removeRelationship($artist->guid, 'fan');

Ceci déclenche l’événement [delete, relationship], en lui passant l’objet ElggRelationship associé. Si un gestionnaire retourne false, la relation sera conservée, et $was_removed vaudra false.

Autres fonctions utiles :

  • \ElggRelationship->delete(): supprime par objet

  • \ElggEntity->removeAllRelationships(): supprime toutes les relations associées à une entité

Contrôle d’accès

Les contrôle d’accès granulaires sont l’un des principes de design fondamentaux dans Elgg, et une fonctionnalité qui a été au cœur du système tout au long de son développement. L’idée est simple : un utilisateur devrait avoir un contrôle total sur qui peut voir un élément de donnée qu’il ou elle a créé.

Niveau d’accès dans le modèle de données

Pour parvenir à cela, chaque entité et annotation contient une propriété access_id, qui correspond à l’un des niveau d’accès prédéfinis ou à une entrée dans la table access_collections de la base de données.

Niveaux d’accès prédéfinis

  • ACCESS_PRIVATE (valeur : 0) Privé.

  • ACCESS_LOGGED_IN (valeur : 1) Utilisateurs connectés.

  • ACCESS_PUBLIC (valeur : 2) Données publiques.

Niveaux d’accès définis par l’utilisateur

Vous pouvez définir des groupes d’accès additionnels et les assigner à une entité, ou une annotation. Un certain nombre de fonctions ont été définies pour vous y aider ; voyez Listes de Contrôle d’Accès pour plus d’informations.

Comment les accès affectent la récupération de données

Toutes les récupérations de données fonctionnent au-dessus de la couche de la base de données - par exemple elgg_get_entities ne retournera que les éléments que l’utilisateur actuel a l’autorisation de voir. Il n’est pas possible de récupérer des éléments auxquels l’utilisateur actuel n’a pas accès. Ceci rend très difficile de créer un trou de sécurité pour récupérer des données.

Accès en écriture

Les règles suivantes gouvernent les accès en écriture :

  • Le propriétaire d’une entité peut toujours la modifier

  • Le propriétaire d’un conteneur peut modifier tout ce qui est dedans (notez que cela ne signifie pas que le propriétaire d’un groupe peut modifier toutes les publications dans ce groupe)

  • Les administrateurs peuvent tout éditer

Vous pouvez remplacer ce comportement en utilisant un event appelé permissions_check, qui transmet l’entité en question à toute fonction ayant annoncé qu’elle souhaite être référencée. Renvoyer true autorisera l’accès en écriture ; renvoyer false le bloquera. Voir le guide de référence des événement pour la vérification des permissions pour plus de détails.

Schéma

La base de données contient un certain nombre de tables primaires et secondaires. Vous pouvez suivre les évolutions du schéma dans engine/schema/migrations/

L’ensemble de caractères de la base de données doit être utf8mb4, ce qui fournira une prise en charge complète des caractères unicode lors du stockage des données.

InnoDB

À partir de Elgg 3.0, la base de données utilise le moteur InnoDB. Pour une installation ou une migration correcte, certains paramètres peuvent devoir être ajustés dans les paramètres de la base de données.

  • innodb_large_prefix devrait être on

  • innodb_file_format devrait être Barracuda

  • innodb_file_per_table devrait être 1

Tables principales

Voici la description des principales tables. Gardez à l’esprit que pour une installation de Elgg donnée, les tables vont avoir un préfixe (typiquement « elgg_ »).

Table : entities - entités

This is the main Entities table containing Elgg users, sites, objects and groups. When you first install Elgg this is automatically populated with your first site, your first user and a set of bundled plugins.

Elle contient les champs suivants :

  • guid Un compteur auto-incrémenté qui produit un GUID qui identifie de manière unique cette entité dans le système

  • type Le type d’entity - object, user, group ou site

  • subtype Le sous-type d’entité

  • owner_guid Le GUID de l’entité du propriétaire

  • container_guid Le GUID dans laquelle cette entité est contenue - soit un utilisateur « user » soit un groupe « group »

  • access_id Contrôles d’accès sur cette entité

  • time_created Le timestamp Unix de création de l’entité

  • time_updated Le timestamp Unix de la dernière modification de l’entité

  • last_action Unix timestamp of when the user last performed an action or when within the entity as container something happened

  • enabled Si “yes” -oui- l’entité est accessible, si “no” -non- l’entité a été désactivée (Elgg traite cela comme si elle avait été supprimée sans toutefois la supprimer réellement de la base de données)

  • deleted If this is “yes” an entity is marked as deleted, if “no” (default) the entity is visible within the regular site. Deleted entities can be viewed in the trash

  • time_deleted Unix timestamp of when the entity was deleted

Table : metadata

Cette table contient des métadonnées Metadata, des informations supplémentaires attachées à une entité.

  • id Un IDentifiant unique

  • entity_guid L’entité à laquelle cette métadonnée est attachée

  • name Le nom de la chaîne

  • value La valeur de la chaîne

  • value_type The value class, either text, bool or an integer

  • time_created Le timestamp Unix de la date de création de la métadonnée

Table : annotations

Cette table contient les Annotations, ce qui est distinct des Metadata.

  • id Un IDentifiant unique

  • entity_guid L’entité à laquelle cette métadonnée est attachée

  • name Le nom de la chaîne

  • value La valeur de la chaîne

  • value_type The value class, either text, bool or an integer

  • owner_guid Le GUID du propriétaire qui a défini cette annotation

  • access_id Un Contrôle d’Accès sur cette annotation

  • time_created Le timestamp Unix de la date de création de l’annotation.

Table : relationships - relations

Cette table définit les relations Relationships, qui relient une entité avec une autre.

  • guid_one Le GUID de l’entité sujet.

  • relationship Le type de relation.

  • guid_two Le GUID de l’entité cible.

  • time_created Unix timestamp of when the relationship is created.

Tables secondaires

Table : access_collections

Cette table définit les Collections d’Accès, qui donnent accès aux utilisateurs aux Entités ou aux Annotations.

  • id Un IDentifiant unique

  • name The name of the access collection

  • owner_guid Le GUID de l’entité propriétaire (par ex. un utilisateur ou un groupe)

  • subtype le sous-type de la collection d’accès (par ex. friends ou group_acl)