Sources de données


1Présentation

Temma propose un mécanisme pour gérer les accès aux sources de données, qui facilite la connexion à ces sources, qui permet de les utiliser de manière unifiée, tout en permettant de faire appel à des capacités spécifiques à chaque source.

Le fonctionnement unifié permet d'utiliser la plupart des sources de données de la même manière, pour écrire et lire des paires clé/valeur. Les sources de données utilisées de cette manière peuvent être interchangées (par exemple, un accès Memcache remplacé par du MySQL ou du Redis ; ou encore une file de message Beanstalkd remplacée par du AWS SQS de manière transparente).


2Configuration

Pour ouvrir une connexion à une source de données, vous devez la configurer dans le fichier etc/temma.php (voir la documentation de la configuration).

[
    // Configuration de l'application
    'application' => [
        'dataSources' => [
            'db'    => 'mysql://user:passwd@localhost/my_base',
            'ndb'   => 'redis://localhost',
            'cache' => 'memcache://localhost',
            'file'  => 'file:///var/data/temma',
            's3'    => 's3://ACCESS_KEY:SECRET_KEY@REGION/my_bucket',
            'sqs'   => 'sqs://ACCESS_KEY:SECRET_KEY@my_queue',
            'mq'    => 'beanstalk://localhost/my_queue',
            'sms'   => 'smsmode://API_KEY',
            'push'  => 'pushover://APP_TOKEN',
            'myDS1' => '[MyDataSource]mydsn://SOME_PARAM',
            'myDS2' => '[\\Namespace\\OtherDataSource]otherdsn://OTHER_PARAM',
        }
    }
}
  • Ligne 5 : Connexion à MySQL.
  • Ligne 6 : Connexion à Redis.
  • Ligne 7 : Connexion à Memcache.
  • Ligne 8 : Accès aux fichiers locaux.
  • Ligne 9 : Connexion à Amazon S3.
  • Ligne 10 : Connexion à Amazon SQS.
  • Ligne 11 : Connexion à Beanstalkd.
  • Ligne 12 : Connexion à smsmode.
  • Ligne 13 : Connexion à Pushover.
  • Ligne 14 : Utilisation de l'objet MyDataSource comme source de données.
  • Ligne 15 : Utilisation de l'objet \Namespace\OtherDataSource comme source de données.

Voyez la documentation de chaque source de données pour en savoir plus sur sa configuration.

Dans les contrôleurs, les sources de données sont directement accessibles en utilisant les noms définis dans la configuration : $this->db, $this->cache, $this->s3, etc.

Dans les objets qui ont accès au composant d'injection de dépendances, il faut passer par le tableau dataSources : $this->_loader->dataSources['db']


3Accès unifié

Les sources de données proposent un certain nombre de méthodes communes pour accéder à des paires clé/valeur. Certaines méthodes ne sont pas toujours utilisables (par exemple, Memcache, Amazon SQS ou encore Beanstalkd ne permettent pas de rechercher parmis les données stockées), mais les principes sont globalement les mêmes.

Il y a trois ensembles de méthodes :

  1. Des méthodes générales (savoir si une donnée existe, effacer des données, etc.).
  2. Des méthodes pour lire et écrire des données complexes. Les données sont sérialisées (au format JSON la plupart du temps, sauf si la source de données propose son propre mécanisme de sérialisation).
  3. Des méthodes pour lire et écrire des données brutes. Ces méthodes manipulent des chaînes de caractères qui sont stockées directement.

Par souci de simplicité, l'accès aux données complexes peut se faire avec une syntaxe de type tableau associatif.


4Accès de type tableau

4.1Existence d'une donnée

Utilisation de la fonction isset().

if (isset($this->source['key1']))
    TµLog::l("La donnée 'key1' existe.");

4.2Lecture d'une donnée

La donnée est désérialisée.

$data = $this->source['key1'];

4.3Écriture d'une donnée

La donnée est sérialisée.

$this->source['key1'] = $data;

4.4Suppression d'une donnée

Utilisation de la fonction unset().

unset($this->source['key1']);

4.5Connaître le nombre de données enregistrées

Utilisation de la fonction count().

$nbr = count($this->source);

5Méthodes générales

5.1isSet()

isSet(string $key) : bool

Retourne true si la clé $key référence une donnée qui existe.

Exemple :

// teste l'existence de la clé "key1"
if (!$this->db->isSet('key1'))
    TµLog::l("Donnée inconnue.");

// écriture alternative
if (!isset($this->db['key1']))
    TµLog::l("Donnée inconnue.");

5.2remove()

remove(string $key) : void

Efface la donnée référencée par la clé $key.

Exemple :

// efface la clé "key1"
$this->cache->remove('key1');

5.3mRemove()

mRemove(array $keys) : void

Efface toutes les données dont les clés sont listées dans le tableau $keys.

Exemple :

// efface les clés "key1" et "key2"
$this->cache->mRemove(['key1', 'key2']);

5.4clear()

clear(string $pattern) : void

Efface toutes les données dont la clé correspond au paramètre fourni. Suivant le fonctionnement de la source de données, le paramètre peut être un préfixe ou un masque d'expression régulière.

Exemple :

// efface tous les fichiers dans le répertoire "images"
$this->files->clear('images/*');

5.5flush()

flush() : void

Efface toutes les données stockées dans la source de données.

Exemple :

// efface tous les fichiers stockés dans un bucket Amazon S3
$this->s3->flush();

6Gestion de données complexes sérialisées

search(string $pattern, bool $getValues=false) : array

Retourne la liste des clés qui correspondent au premier paramètre. Suivant le fonctionnement de la source de données, le paramètre peut être un préfixe ou un masque d'expression régulière.

Si le deuxième paramètre est passé à true, la liste retournée contient les valeurs des données (désérialisées), associées à chaque clé.

Exemples :

// recupère la liste des noms des fichiers dans le répertoire "users"
$users = $this->files->search('users/*');
foreach ($users as $login)
    TµLog::l("Utilisateur : $login");

// récupère la liste des fichiers dans le répertoire "users",
// avec leurs contenus désérialisés
$users = $this->files->search('users/*', true);
foreach ($users as $path => $user) {
    $login = mb_substr($path, mb_strlen('users/'));
    TµLog::l("Utilisateur : $login");
    TµLog::l("Age : " . $user['age']});
    TµLog::l("Adresse : " . $user['address']);
}

6.2get()

get(string $key, mixed $defaultOrCallback=null, mixed $options=null) : mixed

Retourne la donnée (désérialisée) dont la clé est fournie en premier paramètre.

Si la donnée n'existe pas dans la source de données, le deuxième paramètre est utilisé :

  • s'il contient une donnée scalaire, celle-ci est utilisée comme valeur par défaut et est retournée par la méthode ;
  • s'il contient une fonction, celle-ci est exécutée. Sa valeur de retour est ajoutée dans la source de données, associée à la clé fournie, puis elle est retournée par la méthode. Dans ce cas, le troisième paramètre peut recevoir des options qui sont utilisées pour l'enregistrement de la donnée.

Exemples :

// récupération d'une donnée en cache
$colors = $this->cache->get('app:colors');

// écriture alternative
$color = $this->cache['app:colors'];

// idem, mais si la donnée n'est pas en cache, une valeur par défaut est retournée
$colors = $this->cache->get('app:colors', ['blue', 'red', 'green']);
// $colors = ['blue', 'red', 'green'];

// Récupération d'une donnée en cache. Si la donnée n'est pas en cache,
// une fonction est appelée, pour aller chercher la donnée en base
// (en passant par une DAO). La donnée est enregistrée en cache puis
// retournée. La donnée sera disponible lors des accès suivants au cache.
$user = $this->cache->get($userId, function() use ($userId) {
    return $this->_dao->get($userId);
});

6.3mGet()

mGet(array $keys) : array

Prend en paramètre une liste de clés, et retourne un tableau associatif avec les clés et leurs contenus (désérialisés).

Exemple :

// récupère les données (désérialisées) des clés "key1" et "key2"
$data = $this->db->mGet(['key1', 'key2']);
foreach ($data as $key => $datum) {
    TµLog::l("Nom : '$key' - taille : '{$datum['size']}'.");
}

6.4set()

set(string $key, mixed $value=null, mixed $options=null) : mixed

Écrit une donnée (sérialisée) dans la source de données.

  • 1er paramètre : Clé de la donnée à créer ou à mettre à jour.
  • 2e paramètre : Contenu (scalaire ou complexe) de la donnée.
  • 3e paramètre : Option éventuelle utilisée pour l'enregistrement, dépendamment du type de source de données.

Exemple :

// ajout d'une donnée en cache
$this->cache->set('app:color', 'blue');

// écriture alternative
$this->cache['app:color'] = 'blue';

// création d'un fichier texte sur Amazon S3
// avec droits de lecture public
$this->s3->set('text/introduction.txt', $texte, [
    'public'   => true,
    'mimetype' => 'text/plain',
]);

6.5mSet()

mSet(array $data, mixed $options=null) : int

Écrit plusieurs données (sérialisées).

  • 1er paramètre : Tableau associatif dont les clés sont les identifiants des données à écrire, et les valeurs associées sont les contenus des données à écrire.
  • 2e paramètre : Option éventuelle utilisée pour tous les enregistrements, dépendamment du type de source de données.

Exemple :

// écriture de plusieurs clés (sérialisées) dans une base Redis
$this->ndb->mSet([
    'key1' => 'value 1',
    'key2' => ['value 2.1', 'value 2.2', 'value 2.3'],
    'key3' => [
        'key3.1' => 'value 3.1',
        'key3.2' => 'value 3.2',
    ],
]);

7Gestion de données brutes

7.1find()

find(string $pattern, bool $getValues=false) : array

Retourne la liste des clés qui correspondent au premier paramètre. Suivant le fonctionnement de la source de données, le paramètre peut être un préfixe ou un masque d'expression régulière.

Si le deuxième paramètre est passé à true, la liste retournée contient les valeurs (brutes) des données, associées à chaque clé.

Si le deuxième paramètre est laissé à false, cette méthode est identique à la méthode search().

Exemples :

// recupère la liste des noms des fichiers dans le répertoire "images"
$keys = $this->files->find('images/*');
foreach ($keys as $key)
    TµLog::l("Fichier : '$key'.");

// récupère la liste des fichiers dans le répertoire "images",
// avec leurs contenus bruts
$keys = $this->files->find('images/*', true);
foreach ($keys as $key => $value) {
    $size = mb_strlen($value, 'ascii');
    TµLog::l("Fichier : '$key' - taille : '$size'.");
}

7.2read()

read(string $key, mixed $defaultOrCallback=null, mixed $options=null) : mixed

Retourne la donnée dont la clé est fournie en premier paramètre.

Si la donnée n'existe pas dans la source de données, le deuxième paramètre est utilisé :

  • s'il contient une donnée scalaire, celle-ci est utilisée comme valeur par défaut et est retournée par la méthode ;
  • s'il contient une fonction, celle-ci est exécutée. Sa valeur de retour est ajoutée dans la source de données, associée à la clé fournie, puis elle est retournée par la méthode. Dans ce cas, le troisième paramètre peut recevoir des options qui sont utilisées pour l'enregistrement de la donnée.

Exemple :

// Récupération d'un fichier CSS en cache. Si le fichier n'est pas en cache,
// il est lu et ajouté en cache avec une durée de vie de 10 minutes.
$user = $this->cache->read('style.css', function() {
    $css = file_get_contents('/path/to/style.css');
    return ($css);
}, 600);

7.3mRead()

mRead(array $keys) : array

Prend en paramètre une liste de clés, et retourne un tableau associatif avec les clés et leurs contenus.

Exemple :

// lecture de plusieurs données brutes depuis Redis
$data = $this->ndb->mRead(['key1', 'key2', 'key3']);

7.4copyFrom()

copyFrom(string $key, string $localPath, mixed $defaultOrCallback=null, mixed $options=null) : bool

Récupère une donnée et l'enregistre dans un fichier local.

Si la donnée n'existe pas, les troisième et quatrième paramètres sont utilisés pour retourner une valeur par défaut ou pour générer la donnée (voir la méthode read).

Exemple :

// récupère un fichier depuis Amazon S3 et l'enregistre en local
$this->s3->copyFrom('images/user1.jpg', '/var/data/img/login.jpg');

7.5mCopyFrom()

mCopyFrom(array $keys) : int

Prend en paramètre un tableau associatif dont les clés sont les identifiants des données à récupérer, et dont les valeurs associées sont les chemins des fichiers vers lesquels il faut écrire les données.

Exemple :

// récupère plusieurs fichiers depuis Amazon S3 et les enregistre en local
$this->s3->mCopyFrom([
    'images/user1.jpg' => '/var/data/img/login1.jpg',
    'images/user2.jpg' => '/var/data/img/login2.jpg',
]);

7.6write()

write(string $key, string $value, mixed $options=null) : mixed

Écrit une donnée dans la source de données.

  • 1er paramètre : Clé de la donnée à créer ou à mettre à jour.
  • 2e paramètre : Contenu textuel (ou binaire) de la donnée.
  • 3e paramètre : Option éventuelle utilisée pour l'enregistrement, dépendamment du type de source de données.

Exemples :

// écrit une donnée sur un serveur Redis
$this->ndb->write('linux:year', '1991');

// écrit une donnée sur Redis, avec une durée de vie de 10 minutes
$this->ndb->write('linux:year', '1991', 600);

7.7mWrite()

mWrite(array $data, mixed $options=null) : int

Écrit plusieurs données.

  • 1er paramètre : Tableau associatif dont les clés sont les identifiants des données à écrire, et les valeurs associées sont les contenus des données à écrire.
  • 2e paramètre : Option éventuelle utilisée pour tous les enregistrements, dépendamment du type de source de données.

Exemple :

// écrit plusieurs données sur un serveur Redis
$this->ndb->mWrite([
    'qnx'      => '1984',
    'nextstep' => '1988',
    'solaris'  => '1990',
    'linux'    => '1991',
]);

7.8copyTo()

copyTo(string $key, string $localPath, mixed $options=null) : mixed

Écrit une donnée dans la source de données, en y copiant le contenu d'un fichier local.

  • 1er paramètre : Clé de la donnée à créer ou à mettre à jour.
  • 2e paramètre : Chemin vers le fichier source.
  • 3e paramètre : Option éventuelle utilisée pour l'enregistrement, dépendamment du type de source de données.

Exemple :

// copie un fichier local vers Amazon S3
$this->ndb->copyTo('css/style.css', '/var/data/css/style.css');

7.9mCopyTo()

mCopyTo(array $data, mixed $options=null) : int

Écrit plusieurs données, en copiant le contenu de plusieurs fichiers locaux.

  • 1er paramètre : Tableau associatif dont les clés sont les identifiants des données à écrire, et les valeurs associées sont les chemins vers les fichiers sources.
  • 2e paramètre : Option éventuelle utilisée pour tous les enregistrements, dépendamment du type de source de données.

Exemple :

// copie plusieurs fichiers locaux vers Amazon S3
$this->ndb->mCopyTo([
    'css/style.css'    => '/var/data/css/style.css',
    'js/app.js'        => '/var/data/js/app.js',
    'images/login.jpg' => '/var/data/img/login.jpg',
]);

8Gestion des connexions

Habituellement, vous n'avez pas besoin de gérer les connexions. Lors du premier accès (en lecture ou écriture), l'objet se connecte à la source de données. À la destruction de l'objet, la déconnexion est automatique.

Toutefois, il y a de rares cas où l'on souhaite ouvrir ou fermer explicitement la connexion. Les méthodes connect(), reconnect() et disconnect() sont là pour ça.

Toutes les sources de données ne gèrent pas les connexions et déconnexions. Par exemple, la source File ne fait aucune connexion (elle accède aux fichiers désirés au moment de la lecture ou de l'écriture). Les méthodes de connexion/déconnexion peuvent alors quand même être appelées, mais elles ne font rien.


8.1connect()

connect() : void

Effectue la connexion à la source de données.

Si la connexion avait déjà été effectuée, rien ne se passe.


8.2reconnect()

reconnect() : void

Effectue une reconnexion à la source de données.

Si la connexion n'était pas ouverte, elle va l'être. Si un connexion était déjà ouverte, elle est d'abord fermée avant d'être ouverte de nouveau.


8.3disconnect()

disconnect() : void

Ferme la connexion à la source de données.