Utilisation Json comme base de données

26 décembre 2013 nakama

Développement

(Cet article a été écrit il y a très longtemps, dans une galaxie très très lointaine)

Aujourd’hui on va voir comment utiliser le Json comme base de données. L’avantage est de ne plus avoir besoin de MySQL.

Cette solution peut être intéressante pour de petits sites qui ne demandent pas trop d’administration.

Cet article va montrer comment utiliser le format Json et quelques points intéressants 🙂 comme par exemple mettre en place une Api qui va stocker dans un fichier Json des utilisateurs.

Ce qu’il faut garder en tête ici, c’est que chaque fichier Json peut être comparé à une table d’une base de données.

Variables et constructeur

class UserJson {
    private $id;
    private $data;
    private $table;
    private $table_id;
    private $user;
    private $users;

    public function __construct(){
        $this->table    = "users.json";
        $this->table_id = "users_id.txt";

        // si le fichier n'existe pas, on le crée
        if(!file_exists($this->table)){
            $this->createTable();
        }
    }

– mise en place des variables
– le constructeur va renseigner quelques informations : le nom du fichier Json et txt.
– on termine en vérifiant si les fichiers n’existent pas déjà, si ce n’est pas le cas on fera appel à la méthode qui les créera.

Les méthodes

// création des fichiers Json et txt
// le fichier txt servira uniquement à l'incrémentation
public function createTable(){
    $handle    = @fopen($this->table, "a+");
    $handle_id = @fopen($this->table_id, "a+");
    if($handle && $handle_id) {
        fclose($handle);
        fclose($handle_id);
        return true;
    }
}
// Ajout d'un nouvel utilisateur
public function addUser($data){

    // info sur le nouvel user
    $this->data  = $data;

    // on récupère le nouvel ID
    $this->id = $this->getId();

    if( $this->id !== null ){
        // on ajoute l'ID au nouvel user
        $this->data = array('id'=>$this->id) + $this->data;

        // on ajoute le nouvel user au fichier
        $file = @fopen($this->table, 'a+');

        fputs($file, json_encode($this->data).',');

        fclose($file);

        return true;
    }else{
        return "Erreur pour l'ajout de l'utilisateur.";
    }

}

– la méthode getId() récupère un nouvel identifiant qui est contenu dans le fichier txt
– ligne 10 : on teste bien que le résultat n’est pas null sinon c’est qu’il y a eu un problème lors de la création de l’identifiant
– chaque utilisateur est sauvegardé sous cette forme : {« id »:31, »pseudo »: »Iron Man », »date »:1387821811},

// on récupère un nouvel ID
private function getId(){

    if( $txt = @fopen($this->table_id, "r+") ){
        $this->id = fgets( $txt ); // récupération de la valeur
        $this->id = intval( $this->id ); // on vérifie qu’il s’agit bien d’un nombre
        $this->id++; // on incrémente
        fseek( $txt, 0 ); // réinitialisation du curseur
        fputs( $txt, $this->id ); // on écrit le nouveau nombre
        fclose($txt);

        return $this->id;
    }else{
        return null;
    }
}

Une simple méthode pour récupérer la valeur qui se trouve dans le fichier, l’incrémenter et ensuite sauvegarder la nouvelle valeur. J’ai repris la méthode du site openclassrooms pour compter le nombre de téléchargement.

Ici l’élément important : c’est que la méthode est en private, cela signifie qu’on va pouvoir y faire appel uniquement à l’intérieur de la class. Du coup on est certain qu’elle ne peut pas être appelé de l’extérieur, donc un identifiant sera créé uniquement quand on l’appellera dans la class elle-même.

// on récupère un user spécifique
public function getUser($id){

    // l'id de l'user qu'on souhaite récupérer
    $this->id = $id;

    // liste de tous les users
    $datas = $this->getAllUser();

    // on teste si l'id correspond, si oui on renvoie le résultat
    foreach ($datas as $key => $row) {
        if($row->id == $id ) return $row;
    }

    // sinon
    return 'Aucun utilisateur ne correspond.';
}
// liste de tous les users
public function getAllUser(){

    // Si les users sont déjà définis
    if (isset($this->users)) return $this->users;

    // on récupère le contenu du fichier
    $contents    = file_get_contents($this->table);
    $this->users = json_decode("[". substr($contents, 0, -1)."]");

    // on renvoi le tableau des users
    return $this->users;
}

– ligne 5 : elle permet de renvoyer directement tous les utilisateurs si la variable est déjà définie. Cela évite de faire plusieurs fois le travail si on appelle cette méthode plusieurs fois dans un même object
– on récupère le contenu encoder en Json, que l’on va décoder pour pouvoir l’utiliser

Cependant, les données sont sauvegardées de cette manière :

{"id":31,"pseudo":"Iron","date":1387821811},{"id":32,"pseudo":"Iron","date":1387821811},{"id":33,"pseudo":"Iron","date":1387821811},

Et pour pouvoir décoder le format Json les données doivent être comme cela :

[{"id":31,"pseudo":"Iron","date":1387821811},{"id":31,"pseudo":"Iron","date":1387821811},{"id":31,"pseudo":"Iron","date":1387821811}]

C’est pour cela que j’ajoute les [ ] et que je supprime la dernière virgule (ligne 9).

Il est tout à fait possible de faire autrement, enregistrer directement le tableau des utilisateurs, du coup on aura tout de suite la bonne syntaxe. Cependant, pour chaque ajout il faudrait tout récupérer et ré-écrire à chaque fois … perso je préfère écrire uniquement le nouvel utilisateur ^^

// modification d'un utilisateur
public function updateUser($id, $data){
    $this->id    = $id;
    $this->data  = $data;

    // liste de tous les users
    $this->users = $this->getAllUser();

    // on ouvre et on vide le fichier
    if($handle = @fopen($this->table, "w+")) {
        $this->data = "";
        foreach ($this->users as $key => $row) {
            // si l'id correspond
            // on modifie le nouveau pseudo par exemple
            if( $row->id == $this->id ){
                if($data['pseudo'] != "") $row->pseudo = $data['pseudo'];
            }

            $this->data .= json_encode($row).',';
        }
        // on ajoute tous les utilisateurs dans le fichier
        fputs($handle, $this->data);

        fclose($handle);
        return true;
    }
}
// suppression d'un utilisateur
public function removeUser($id){
    $this->id    = $id;

    // liste tous les users
    $this->users = $this->getAllUser();

    if($handle = @fopen($this->table, "w+")) {
        $this->data = "";
        foreach ($this->users as $key => $row) {
            if($row->id == $this->id )
                unset($this->users[$key]);
            else
                $this->data .= json_encode($row).',';
        }

        fputs($handle, $this->data);

        fclose($handle);
        return true;
    }

}

La suppression se passe plus ou moins comme la modification, on regarde si l’id correspond, si oui on le supprime du tableau des utilisateurs et ensuite on ré-écrit le tout dans le fichier.

On n’oublie pas la dernière accolade de la class 🙂

}

C’est fini

La class permet de créer, de modifier, de supprimer et de lister tous les utilisateurs. Évidemment, elle peut être améliorée 🙂 ici je propose uniquement une base comme exemple 🙂

Mais il ne manque rien ?

Il manque peut-être les appels à la class 🙂 enfin la création de l’object.

// initialisation
$json = new UserJson();

// liste de tous les utilisateurs
print_r( $json->getAllUser() );

// appel d'un utilisateur spécifique
print_r( $json->getUser(31) );

// ajout d'un nouvel utilisateur
$user = array('pseudo' => 'Batman', 'date'=>time());
var_dump( $json->addUser($user) );

// modification d'un utilisateur
$update = array('pseudo'=>'Thor');
var_dump( $json->updateUser(44, $update) );

// suppression d'un utilisateur
print_r( $json->removeUser(42) );

Idées d’amélioration ?

– Pseudo et email unique
– Rajouter des champs : mdp, email, date de modification etc.
– Mettre en place une 2e table pour classer les utilisateurs par catégories
– Mettre en place un système d’identification (login/mdp)
– etc.

Mots-clés associés à cet article :

Retrouvez d'autres articles par catégories