Un magasin de documents pour PHP qui permet des conmises multiples. Il s'agit d'une alternative minimaliste à MongoDB ou CouchDB sans les frais généraux de l'installation d'un nouveau service.
Il fonctionne également comme une petite base de données d'empreintes.
En moyenne, une PME génère 100 factures par mois. Disons donc qu'un SMB génère 12 000 factures par décennie.
Test de génération de 12000 factures avec client, détails (environ 1 à 5 lignes par détail) et date d'un i7 / ssd / 16 Go / Windows 64Bits.

Un test avec 100 tests simultanés (écrire et lire), 10 fois.
| N ° | Lecture | (MS) | Lecture | Erreur |
|---|---|---|---|---|
| 1 | 100 | 7471 | 100 | 0 |
| 2 | 100 | 7751 | 100 | 0 |
| 3 | 100 | 7490 | 100 | 0 |
| 4 | 100 | 7480 | 100 | 0 |
| 5 | 100 | 8199 | 100 | 0 |
| 6 | 100 | 7451 | 100 | 0 |
| 7 | 100 | 7476 | 100 | 0 |
| 8 | 100 | 7244 | 100 | 0 |
| 9 | 100 | 7573 | 100 | 0 |
| 10 | 100 | 7818 | 100 | 0 |
include " lib/DocumentStoreOne.php " ;
use eftec DocumentStoreOne DocumentStoreOne ;
try {
$ flatcon = new DocumentStoreOne ( " base " , ' tmp ' );
// or you could use:
// $flatcon = new DocumentStoreOne(__DIR__ . "/base", 'tmp');
} catch ( Exception $ e ) {
die ( " Unable to create document store. Please, check the folder " );
}
$ flatcon -> insertOrUpdate ( " somekey1 " , json_encode ( array ( " a1 " => ' hello ' , " a2 " => ' world ' ))); // or you could use serialize/igbinary_serialize
$ doc = $ flatcon -> get ( " somekey1 " );
$ listKeys = $ flatcon -> select ();
$ flatcon -> delete ( " somekey1 " ); include " lib/DocumentStoreOne.php " ;
use eftec DocumentStoreOne DocumentStoreOne ;
$ doc = new DocumentStoreOne ( " base " , " task " , ' folder ' );
//also: $doc=new DocumentStoreOne(__DIR__."/base","task",'folder');
$ doc -> serializeStrategy = ' php ' ; // it sets the strategy of serialization to php
$ doc -> autoSerialize ( true ); // autoserialize
$ flatcon -> insertOrUpdate ( " somekey1 " , array ( " a1 " => ' hello ' , " a2 " => ' world ' )); Il crée l'instance DocumentStoreOne.
| stratégie | taper | serveur | référence |
|---|---|---|---|
| Dso_auto | Il définit la meilleure stratégie disponible (par défaut) | dépend | - |
| Dso_folder | Il utilise un dossier pour verrouiller / déverrouiller un document | - | 0,3247 |
| Dso_apcu | Il utilise APCU pour verrouiller / déverrouiller un document | - | 0.1480 |
| Dso_redis | Il utilise Redis pour verrouiller / déverrouiller un document | Host local: 6379 | 2.5403 (pire) |
| Dso_none | Il n'utilise rien pour verrouiller / déverrouiller un document. C'est la méthode la plus rapide, mais elle est dangereuse pour les utilisateurs multiples | 0 |
| stratégie | taper |
|---|---|
| php | Il sérialise en utilisant la fonction sérialize () |
| php_array | Il sérialise en utilisant la fonction include () / var_export (). Le résultat pourrait être mis en cache sur OPCACH car le résultat est un fichier de code PHP. |
| json_object | il est sérialisé à l'aide de JSON (comme objet) |
| json_array | Il est sérialisé à l'aide de JSON (comme tableau) |
| CSV | Il sérialise à l'aide d'un fichier CSV. |
| igbinar | Il sérialise à l'aide d'un fichier igbinaire. |
| Aucun (valeur par défaut) | il n'est pas sérialisé. Les informations doivent être sérialisées / désérialisées manuellement |
Exemples:
$ flatcon = new DocumentStoreOne ( __DIR__ . " /base " ); // new instance, using the folder /base, without serialization and with the default data
$ flatcon = new DocumentStoreOne ( __DIR__ . " /base " , '' , ' auto ' , '' , ' php_array ' ); // new instance and serializing using php_arrayComparez la quantité de temps (en secondes) qu'il faut pour ajouter 100 inserts.
use eftec DocumentStoreOne DocumentStoreOne ;
include " lib/DocumentStoreOne.php " ;
try {
$ flatcon = new DocumentStoreOne ( __DIR__ . " /base " , ' tmp ' );
} catch ( Exception $ e ) {
die ( " Unable to create document store. " . $ e -> getMessage ());
} use eftec DocumentStoreOne DocumentStoreOne ;
include " lib/DocumentStoreOne.php " ;
try {
$ flatcon = new DocumentStoreOne ( " /base " , ' tmp ' ,DocumentStoreOne:: DSO_APCU );
} catch ( Exception $ e ) {
die ( " Unable to create document store. " . $ e -> getMessage ());
}Renvoie True si la collection est valide (un sous-fichier).
$ ok = $ flatcon -> isCollection ( ' tmp ' );Il définit la collection actuelle
$ flatcon -> collection ( ' newcollection ' ); // it sets a collection.Cette commande pourrait être imbriquée.
$ flatcon -> collection ( ' newcollection ' )-> select (); // it sets and return a queryRemarque, il ne valide pas si la collection est correcte ou existe. Vous devez utiliser IsCollection () pour vérifier si c'est juste.
Il définit si nous voulons sérialiser automatiquement les informations et nous définissons la façon dont il est sérialisé. Vous pouvez également définir à l'aide du constructeur.
| stratégie | taper |
|---|---|
| php | Il sérialise en utilisant la fonction sérialize (). |
| php_array | Il sérialise en utilisant la fonction include () / var_export (). Le résultat pourrait être mis en cache sur Opcache car le résultat est un fichier PHP |
| json_object | il est sérialisé à l'aide de JSON (comme objet) |
| json_array | Il est sérialisé à l'aide de JSON (comme tableau) |
| CSV | Il sérialise à l'aide d'un fichier CSV. |
| igbinar | Il sérialise à l'aide d'un fichier igbinaire. |
| Aucun (valeur par défaut) | il n'est pas sérialisé. Les informations doivent être sérialisées / désérialisées manuellement |
Il crée une collection (un nouveau dossier à l'intérieur du dossier de base). Il renvoie False si l'opération échoue; Sinon, il renvoie vrai
$ flatcon -> createCollection ( ' newcollection ' );
$ flatcon -> createCollection ( ' /folder1/folder2 ' ); Insère un nouveau document (chaîne) dans le $ id indiqué. Si le document existe, il est mis à jour.
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut de tentatives).
// if we are not using auto serialization
$ doc = json_encode ([ " a1 " => ' hello ' , " a2 " => ' world ' ]);
$ flatcon -> insertOrUpdate ( " 1 " , $ doc ); // it will create a document called 1.dson in the base folder.
// if we are using auto serialization
$ flatcon -> insertOrUpdate ( " 1 " ,[ " a1 " => ' hello ' , " a2 " => ' world ' ]);Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais équivalent à 10 secondes)
C'est plus rapide que d'insérer ou de mettre à jour.
Insère un nouveau document (chaîne) dans le $ id indiqué. Si le document existe, il renvoie False.
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut de tentatives).
// if we are not using auto serialization
$ doc = json_encode ( array ( " a1 " => ' hello ' , " a2 " => ' world ' ));
$ flatcon -> insert ( " 1 " , $ doc );
// if we are using auto serialization
$ flatcon -> insert ( " 1 " ,[ " a1 " => ' hello ' , " a2 " => ' world ' ]);Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais équivalent à 10 secondes)
Mettez à jour un document (chaîne) dans l' ID $ indiqué. Si le document n'existe pas, alors il renvoie faux
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut de tentatives).
// if we are not using auto serialization
$ doc = json_encode ([ " a1 " => ' hello ' , " a2 " => ' world ' ]);
$ flatcon -> update ( " 1 " , $ doc );
// if we are using auto serialization
$ flatcon -> update ( " 1 " ,[ " a1 " => ' hello ' , " a2 " => ' world ' ]);Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais qui équivaut à 10 secondes)
Il lit le document $ id . Si le document n'existe pas ou qu'il n'est pas en mesure de le lire, il renvoie faux.
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut de tentatives).
$ doc = $ flatcon -> get ( " 1 " ); // the default value is false
$ doc = $ flatcon -> get ( " 1 " ,- 1 , ' empty ' );Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais équivalent à 10 secondes)
Il lit le document $ id filtré. Si le document n'existe pas ou qu'il n'est pas en mesure de le lire, il renvoie faux.
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut de tentatives).
// data in rows [['id'=>1,'cat'=>'vip'],['id'=>2,'cat'=>'vip'],['id'=>3,'cat'=>'normal']];
$ data = $ this -> getFiltered ( ' rows ' ,- 1 , false ,[ ' cat ' => ' normal ' ]); // [['id'=>3,'cat'=>'normal']]
$ data = $ this -> getFiltered ( ' rows ' ,- 1 , false ,[ ' type ' => ' busy ' ], false ); // [2=>['id'=>3,'cat'=>'normal']]Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais équivalent à 10 secondes)
Il ajoute une valeur à un document avec le nom $ nom . La nouvelle valeur est ajoutée, il évite donc de créer l'intégralité du document. Il est utile, par exemple, pour un fichier journal.
a) Si la valeur n'existe pas, il est créé avec $ addValue. Sinon, il reviendra vrai
b) Si la valeur existe, alors $ addValue est ajouté, et il reviendra vrai
c) Sinon, il reviendra faux
$ seq = $ flatcon -> appendValue ( " log " , date ( ' c ' ). " new log " );Il lit ou génère une nouvelle séquence.
A) Si la séquence existe, elle est incrémentée par l'intervalle $ et cette valeur est renvoyée.
b) Si la séquence n'existe pas, elle est créée avec $ init et que cette valeur est renvoyée. c) Si la bibliothèque n'est pas en mesure de créer une séquence, incapable de verrouiller ou que la séquence existe mais qu'il est incapable de lire, alors il renvoie faux
$ seq = $ flatcon -> getNextSequence ();Vous pouvez jeter un œil à une séquence avec $ id = get ('genSeq_') mais ce n'est pas recommandé.
Si la séquence est corrompue, elle est réinitialisée à $ init
Si vous devez réserver une liste de séquences, vous pouvez utiliser $ réservedditional
$ seq = $ flatcon -> getNextSequence ( " seq " ,- 1 , 1 , 1 , 100 ); // if $seq=1, then it's reserved up to the 101. The next value will be 102.Il renvoie une séquence unique (64 bits entier) basé sur le temps, une valeur aléatoire et un serverid.
Les chances de collision (une génération de la même valeur) sont de 1/4095 (par deux opérations exécutées chaque 0,0001 seconde).
$ this -> nodeId = 1 ; // if it is not set then it uses a random value each time.
$ unique = $ flatcon -> getSequencePHP (); Il vérifie si le document $ id existe. Il revient vrai si le document existe. Sinon, il renvoie faux.
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut d'essais).
La validation ne se produit que si le document est entièrement déverrouillé.
$ found = $ flatcon -> ifExist ( " 1 " );Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais qui équivaut à 10 secondes)
Il supprime le document $ id . Si le document n'existe pas ou qu'il n'est pas en mesure de supprimer, il renvoie faux.
$ essais indique le nombre d'essais. La valeur par défaut est -1 (nombre par défaut d'essais).
$ doc = $ flatcon -> delete ( " 1 " );Si le document est verrouillé, il se réjouit jusqu'à ce qu'il soit disponible ou après un nombre "nth" d'essais (par défaut, il est de 100 essais qui équivaut à 10 secondes)
Il renvoie tous les ID stockés sur une collection.
$ listKeys = $ flatcon -> select ();
$ listKeys = $ flatcon -> select ( " invoice_* " );Il comprend des documents verrouillés.
Copiez le document $ idorigin dans $ idDestination
$ bool = $ flatcon -> copy ( 20 , 30 );Si la destination du document existe, alors elle est remplacée
Renommez le document $ idorigin comme $ iddeStination
$ bool = $ flatcon -> rename ( 20 , 30 );Si la destination du document existe, l'opération échoue.
Il convertit une STDClass en une classe spécifique.
$ inv = new Invoice ();
$ invTmp = $ doc -> get ( ' someid ' ); //$invTmp is a stdClass();
DocumentStoreOne:: fixCast ( $ inv , $ invTmp ); Cela ne fonctionne pas avec des membres qui sont des objets. Le tableau est conservé sous forme de stdclass.
Les champs suivants sont publics, et ils pourraient être modifiés pendant l'exécution
| champ | Taper |
|---|---|
| $ Base de données | dossier racine de chaîne de la base de données |
| $ Collection | COLLECTE DE COURANT COURANT (Sous-dossier) de la base de données |
| $ maxlocktime = 120 | Int maximium Durée de la serrure (en secondes). Par défaut, c'est 2 minutes |
| $ defaultnumrety = 100 | Int Nombre de tentatives par défaut. Par défaut, il essaie 100x0.1sec = 10 secondes |
| $ intercalbetwereretry = 100000 | intervalle int (en microsecondes) entre les tentatives. 100000 signifie 0,1 seconde |
| $ docext = ". DSON" | Extension par défaut de chaîne (avec point) du document |
| $ keyencryption = "" | La chaîne indique si la clé est cryptée ou non lorsqu'elle est stockée (le nom du fichier). Des moyens vides, pas de cryptage. Vous pouvez utiliser MD5, SHA1, SHA256, .. |
Exemple:
$ ds = new DocumentStoreOne ();
$ ds -> maxLockTime = 300 ; $ ds = new DocumentStoreOne ();
$ ds -> insert ( ' 1 ' , ' hello ' ); // it stores the document 1.dson
$ ds -> keyEncryption = ' SHA256 ' ;
$ ds -> insert ( ' 1 ' , ' hello ' ); // it stores the document 6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b.dson Cela pourrait être fait manuellement. Le système permet de stocker une valeur pré-calculée qui pourrait être facilement accès (au lieu de lire toutes les valeurs).
Disons le prochain exercice, nous avons une liste d'achats
| identifiant | client | âge | sexe | ProductPurchase | montant |
|---|---|---|---|---|---|
| 14 | John | 33 | m | 33 | 3 |
| 25 | anna | 22 | f | 32 | 1 |
| code de produit | prix unitaire |
|---|---|
| 32 | 23.3 |
| 33 | 30 |
John a acheté 3 produits avec le code 33. Les produits 33 coûtent 23,3 $ par unité.
Question, combien de chaque client a payé?.
C'est un exercice simple, il est plus adapté à une base de données relationnelle (sélectionnez * dans les achats de produits de jointure intérieure). Cependant, si le document est long ou complexe à stocker dans la base de données, c'est ici où un magasin de documents brille.
// 1) open the store
$ ds = new DocumentStoreOne ( ' base ' , ' purchases ' ); // we open the document store and selected the collection purchase.
$ ds -> autoSerialize ( true , ' auto ' );
// 2) reading all products
// if the list of products holds in memory then, we could store the whole list in a single document (listproducts key)
$ products = $ ds -> collection ( ' products ' )-> get ( ' listproducts ' );
// 3) we read the keys of every purchases. It could be slow and it should be a limited set (<100k rows)
$ purchases = $ ds -> collection ( ' purchases ' )-> select (); // they are keys such as 14,15...
$ customerXPurchase =[];
// 4) We read every purchase. It is also slow. Then we merge the result and obtained the final result
foreach ( $ purchases as $ k ) {
$ purchase = $ ds -> get ( $ k );
@ $ customerXPurchase [ $ purchase -> customer ]+=( $ purchase -> amount * @ $ products [ $ purchase -> productpurchase ]); // we add the amount
}
// 5) Finally, we store the result.
$ ds -> collection ( ' total ' )-> insertOrUpdate ( $ customerXPurchase , ' customerXPurchase ' ); // we store the result.| client | valeur |
|---|---|
| John | 69.9 |
| anna | 30 |
Puisqu'il est fait sur le code, il est possible de créer un système hybride (base de données relationnelle + magasin + cache de mémoire)
Disons que nous voulons sérialiser les informations suivantes:
$ input =[[ ' a1 ' => 1 , ' a2 ' => ' a ' ],[ ' a1 ' => 2 , ' a2 ' => ' b ' ]];Les valeurs ne sont pas sérialisées, il n'est donc pas possible de sérialiser un objet, un tableau ou une autre structure. Cela ne fonctionne qu'avec des cordes.
Comment les valeurs sont stockées
helloworld
Comment les valeurs sont renvoyées
" helloworld " La sérialisation de PHP est l'un des moyens plus rapides de sérialiser et de désérialiser, et il renvoie toujours la même valeur avec la même structure (classes, tableau, champs)
Cependant, la valeur stockée pourrait être longue.
Comment les valeurs sont stockées:
a:2:{i:0;a:2:{s:2:"a1";i:1;s:2:"a2";s:1:"a";}i:1;a:2:{s:2:"a1";i:2;s:2:"a2";s:1:"b";}}
Comment les valeurs sont renvoyées:
[['a1'=>1,'a2'=>'a'],['a1'=>2,'a2'=>'b']]
Cette sérialisation génère un code PHP. Ce code est verbeux cependant, il a de belles fonctionnalités:
Comment les valeurs sont stockées:
<?php /** @generated */
return array (
0 =>
array (
' a1 ' => 1 ,
' a2 ' => ' a ' ,
),
1 =>
array (
' a1 ' => 2 ,
' a2 ' => ' b ' ,
),
);Comment les valeurs sont renvoyées:
[['a1'=>1,'a2'=>'a'],['a1'=>2,'a2'=>'b']]
Les deux méthodes fonctionnent avec JSON pour la sérialisation et la désérialisation, mais la première sur retourne toujours un tableau associatif tandis que l'autre pourrait renvoyer un objet (stdclass)
Pro:
Inconvénients:
Comment les valeurs sont stockées:
[{"a1":1,"a2":"a"},{"a1":2,"a2":"b"}]
Comment les valeurs sont renvoyées:
[[ ' a1 ' => 1 , ' a2 ' => ' a ' ],[ ' a1 ' => 2 , ' a2 ' => ' b ' ]] // array
[stdClass{ ' a1 ' => 1 ,'a2'=>'a'},stdClass{ ' a1 ' => 2 ,'a2'=>'b'}] // objectPar défaut, cette bibliothèque jette des erreurs lorsqu'une erreur ou une exception se produit. Certaines méthodes permettent d'éviter de lancer des erreurs, mais la plupart d'entre elles pourraient lancer une erreur.
Les erreurs sont des captures d'essai / capt.
// throw an error:
$ this -> throwable = true ; // (default value is true) If false, then the errors are stored in $this->latestError
try {
$ this -> insert ( ' id1 ' , ' values ' );
} catch ( $ ex ) {
var_dump ( $ ex );
} // not throw an error:
$ this -> throwable = false ;
$ this -> insert ( ' id1 ' , ' values ' );
if ( $ this -> latestError ) {
var_dump ( $ this -> latestError );
}
$ this -> resetError ();Ou vous pouvez également utiliser pour éviter de lancer une exception:
// not throw an error:
$ this ->-> noThrowOnError ()-> insert ( ' id1 ' , ' values ' );
// but you can still see the latest error:
if ( $ this -> latestError ) {
var_dump ( $ this -> latestError );
}Vous pouvez travailler avec CSV comme suit:
$ doc = new DocumentStoreOne ( __DIR__ . " /base " , '' , ' none ' , '' , ' csv ' ); // set your strategy to csv.
$ doc -> docExt = ' .csv ' ; // (optional), you can set the extension of the document
$ doc -> csvPrefixColumn = ' col_ ' ; // (optional), you can set the name of the columns (if the csv doesn't have columns)
$ doc -> csvStyle (); // (optional) not needing, but you can use to set your own specifications of csv, for example tab-separated, etc.
$ doc -> regionalStyle (); // (optional) not needing, but you can use to set your own regional settings.
$ values =[
[ ' name ' => ' john1 ' , ' age ' => 22 ],
[ ' name ' => ' john2 ' , ' age ' => 22 ],
[ ' name ' => ' john3 ' , ' age ' => 22 ],
];
$ doc -> delete ( ' csv1 ' );
$ doc -> insert ( ' csv1 ' , $ values );[RuntimeException] n'a pas pu charger le package eftec / documentStoreOne dans repo.packagist.org: [inattenduValueException] n'a pas pu analyser la contrainte de version ^ 5.6. : Chaîne de version non valide "^ 5.6. "