Un almacén de documentos para PHP que permite concurrencias múltiples. Es una alternativa minimalista a MongoDB o CouchDB sin la sobrecarga de instalar un nuevo servicio.
También funciona como una pequeña base de datos de huella.
En promedio, una SMB genera 100 facturas por mes. Entonces, digamos que una SMB genera 12000 facturas por década.
Prueba de generación de 12000 facturas con el cliente, detalles (alrededor de 1-5 líneas por detalle) y datan de un i7/ssd/16GB/Windows 64bits.

Una prueba con 100 pruebas concurrentes (escribir y leer), 10 veces.
| N ° | Lectura | (EM) | Lectura | Error |
|---|---|---|---|---|
| 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 ' )); Crea la instancia de DocumentStoreOne.
| estrategia | tipo | servidor | punto de referencia |
|---|---|---|---|
| Dso_auto | Establece la mejor estrategia disponible (predeterminado) | depende | - |
| Dso_folder | Utiliza una carpeta para bloquear/desbloquear un documento | - | 0.3247 |
| Dso_apcu | Utiliza APCU para bloquear/desbloquear un documento | - | 0.1480 |
| Dso_redis | Utiliza Redis para bloquear/desbloquear un documento | Localhost: 6379 | 2.5403 (peor) |
| Dso_none | No usa nada para bloquear/desbloquear un documento. Es el método más rápido, pero no es seguro para los usuarios de múltiples | 0 |
| estrategia | tipo |
|---|---|
| php | Es serialización usando la función Serialize () |
| php_array | Es serializa usando la función incluir ()/var_export (). El resultado podría almacenarse en caché en OpCache porque el resultado es un archivo de código PHP. |
| JSON_Object | se está serializado usando JSON (como objeto) |
| json_array | se está serializado usando JSON (como matriz) |
| CSV | Es seriale usando un archivo CSV. |
| igbinario | Es seriale usando un archivo igbinario. |
| Ninguno (valor predeterminado) | no está serializado. La información debe ser serializada/deserializada manualmente |
Ejemplos:
$ 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_arrayCompare cuánto tiempo (en segundos) se necesita para agregar 100 insertos.
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 ());
}Devuelve verdadero si la colección es válida (un subcarpeta).
$ ok = $ flatcon -> isCollection ( ' tmp ' );Establece la colección actual
$ flatcon -> collection ( ' newcollection ' ); // it sets a collection.Este comando podría estar anidado.
$ flatcon -> collection ( ' newcollection ' )-> select (); // it sets and return a queryTenga en cuenta que no valida si la colección es correcta o existe. Debe usar iSCollection () para verificar si es correcto.
Establece si queremos serializar automáticamente la información, y establecemos cómo se está serializado. También puede configurar utilizando el constructor.
| estrategia | tipo |
|---|---|
| php | Es serialización usando la función Serialize (). |
| php_array | Es serializa usando la función incluir ()/var_export (). El resultado podría almacenarse en caché en OpCache porque el resultado es un archivo PHP |
| JSON_Object | se está serializado usando JSON (como objeto) |
| json_array | se está serializado usando JSON (como matriz) |
| CSV | Es seriale usando un archivo CSV. |
| igbinario | Es seriale usando un archivo igbinario. |
| Ninguno (valor predeterminado) | no está serializado. La información debe ser serializada/deserializada manualmente |
Crea una colección (una nueva carpeta dentro de la carpeta base). Devuelve falso si la operación falla; De lo contrario, devuelve verdadero
$ flatcon -> createCollection ( ' newcollection ' );
$ flatcon -> createCollection ( ' /folder1/folder2 ' ); Inserta un nuevo documento (cadena) en el ID $ indicado. Si el documento existe, entonces se actualiza.
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
// 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 el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos equivalentes a 10 segundos)
Es más rápido que insertar o actualizar.
Inserta un nuevo documento (cadena) en el ID $ indicado. Si el documento existe, entonces devuelve falso.
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
// 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 el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos equivalentes a 10 segundos)
Actualizar un documento (cadena) en el ID $ indicado. Si el documento no existe, entonces devuelve falso
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
// 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 el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos que equivalen a 10 segundos)
Lee el documento $ ID . Si el documento no existe, o no puede leerlo, entonces devuelve falso.
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
$ doc = $ flatcon -> get ( " 1 " ); // the default value is false
$ doc = $ flatcon -> get ( " 1 " ,- 1 , ' empty ' );Si el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos equivalentes a 10 segundos)
Lee el documento $ ID filtrado. Si el documento no existe, o no puede leerlo, entonces devuelve falso.
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
// 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 el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos equivalentes a 10 segundos)
Agrega un valor a un documento con nombre $ nombre . Se agrega el nuevo valor, por lo que evita crear todo el documento. Es útil, por ejemplo, para un archivo de registro.
a) Si el valor no existe, entonces se crea con $ addValue. De lo contrario, devolverá verdadero
b) Si el valor existe, entonces se agrega $ addValue y devolverá verdadero
c) de lo contrario, devolverá falso
$ seq = $ flatcon -> appendValue ( " log " , date ( ' c ' ). " new log " );Lee o genera una nueva secuencia.
a) Si la secuencia existe, entonces se incrementa por $ intervalo y se devuelve este valor.
b) Si la secuencia no existe, entonces se crea con $ init , y este valor se devuelve. c) Si la biblioteca no puede crear una secuencia, no se puede bloquear o la secuencia existe, pero no puede leer, entonces devuelve falso
$ seq = $ flatcon -> getNextSequence ();Puede echar un vistazo a una secuencia con $ id = get ('Genseq_') sin embargo, no se recomienda.
Si la secuencia es corrupta, entonces se restablece a $ init
Si necesita reservar una lista de secuencias, puede usar $ Reservadditional
$ 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.Devuelve una secuencia única (entero de 64 bits) basado en el tiempo, un valor aleatorio y un servidor.
Las posibilidades de colisión (una generación del mismo valor) son 1/4095 (por dos operaciones ejecutadas cada 0.0001 segundos).
$ this -> nodeId = 1 ; // if it is not set then it uses a random value each time.
$ unique = $ flatcon -> getSequencePHP (); Verifica si existe el documento $ ID . Devuelve verdadero si existe el documento. De lo contrario, devuelve falso.
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
La validación solo ocurre si el documento está completamente desbloqueado.
$ found = $ flatcon -> ifExist ( " 1 " );Si el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos que equivalen a 10 segundos)
Elimina el documento $ id . Si el documento no existe, o no puede eliminar, entonces devuelve falso.
$ intentos indica el número de intentos. El valor predeterminado es -1 (número predeterminado de intentos).
$ doc = $ flatcon -> delete ( " 1 " );Si el documento está bloqueado, entonces se vuelve hasta que esté disponible o después de un número "enésimo" de intentos (por defecto, son 100 intentos que equivalen a 10 segundos)
Devuelve todas las ID almacenadas en una colección.
$ listKeys = $ flatcon -> select ();
$ listKeys = $ flatcon -> select ( " invoice_* " );Incluye documentos bloqueados.
Copie el documento $ Idorigin en $ Iddestination
$ bool = $ flatcon -> copy ( 20 , 30 );Si el destino del documento existe, entonces se reemplaza
Cambie el nombre del documento $ Idorigin como $ IdDestination
$ bool = $ flatcon -> rename ( 20 , 30 );Si el destino del documento existe, la operación falla.
Convierte una clase STD a una clase específica.
$ inv = new Invoice ();
$ invTmp = $ doc -> get ( ' someid ' ); //$invTmp is a stdClass();
DocumentStoreOne:: fixCast ( $ inv , $ invTmp ); No funciona con los miembros que son una matriz de objetos. La matriz se guarda como Clase STD.
Los siguientes campos son públicos, y podrían cambiarse durante el tiempo de ejecución
| campo | Tipo |
|---|---|
| $ Base de datos | Cadena de la carpeta raíz de la base de datos |
| $ COLECCIÓN | String Current Collection (subcarpeta) de la base de datos |
| $ maxlocktime = 120 | int Maximium Duración del bloqueo (en segundos). Por defecto son 2 minutos |
| $ DefaultNumretry = 100 | int predeterminado número de reintentos. Por defecto, intenta 100x0.1sec = 10 segundos |
| $ IntervalBetWewerRetry = 100000 | Intervalo int (en microsegundos) entre reintentos. 100000 significa 0.1 segundos |
| $ docext = ". dson" | Extensión predeterminada de cadena (con DOT) del documento |
| $ KeyEnnttion = "" | La cadena indica si la clave está encriptada o no cuando se almacena (el nombre del archivo). Medios vacíos, sin cifrado. Podrías usar MD5, Sha1, Sha256, .. |
Ejemplo:
$ 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 Se podría hacer manualmente. El sistema permite almacenar un valor precalculado que podría acceder fácilmente (en lugar de leer todos los valores).
Digamos el próximo ejercicio, tenemos una lista de compras
| identificación | cliente | edad | sexo | compraz de productos | cantidad |
|---|---|---|---|---|---|
| 14 | John | 33 | metro | 33 | 3 |
| 25 | Anna | 22 | F | 32 | 1 |
| código de productos | precio de la unidad |
|---|---|
| 32 | 23.3 |
| 33 | 30 |
John compró 3 productos con el código 33. Los productos 33 cuestan $ 23.3 por unidad.
Pregunta, ¿cuánto pagó todos los clientes?
Es un ejercicio simple, es más adecuado para una base de datos relacional (seleccione * de compras de productos de unión interna). Sin embargo, si el documento es largo o complejo de almacenar en la base de datos, entonces es aquí donde brilla una tienda de documentos.
// 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.| cliente | valor |
|---|---|
| John | 69.9 |
| Anna | 30 |
Dado que se realiza en código, entonces es posible crear un sistema híbrido (base de datos relacional+almacenamiento+caché de memoria)
Digamos que queremos serializar la siguiente información:
$ input =[[ ' a1 ' => 1 , ' a2 ' => ' a ' ],[ ' a1 ' => 2 , ' a2 ' => ' b ' ]];Los valores no se serializan, por lo que no es posible serializar un objeto, matriz u otra estructura. Solo funciona con cuerdas.
Cómo se almacenan los valores
helloworld
Cómo se devuelven los valores
" helloworld " La serialización de PHP es una de las formas más rápidas de serializar y deserializar, y siempre devuelve el mismo valor con la misma estructura (clases, matriz, campos)
Sin embargo, el valor almacenado podría ser largo.
Cómo se almacenan los valores:
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";}}
Cómo se devuelven los valores:
[['a1'=>1,'a2'=>'a'],['a1'=>2,'a2'=>'b']]
Esta serialización genera un código PHP. Este código es detallado, sin embargo, tiene algunas características agradables:
Cómo se almacenan los valores:
<?php /** @generated */
return array (
0 =>
array (
' a1 ' => 1 ,
' a2 ' => ' a ' ,
),
1 =>
array (
' a1 ' => 2 ,
' a2 ' => ' b ' ,
),
);Cómo se devuelven los valores:
[['a1'=>1,'a2'=>'a'],['a1'=>2,'a2'=>'b']]
Ambos métodos funcionan con JSON para la serialización y des-serialización, pero el primero en devolver siempre una matriz asociativa, mientras que el otro podría devolver un objeto (stdclass)
Pro:
Contras:
Cómo se almacenan los valores:
[{"a1":1,"a2":"a"},{"a1":2,"a2":"b"}]
Cómo se devuelven los valores:
[[ ' a1 ' => 1 , ' a2 ' => ' a ' ],[ ' a1 ' => 2 , ' a2 ' => ' b ' ]] // array
[stdClass{ ' a1 ' => 1 ,'a2'=>'a'},stdClass{ ' a1 ' => 2 ,'a2'=>'b'}] // objectPor defecto, esta biblioteca arroja errores cuando ocurre un error o excepción. Algunos métodos permiten evitar tirar errores, pero la mayoría de ellos podrían arrojar un error.
Los errores son pruebas/capturan las capturas.
// 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 ();O también podría usar para evitar lanzar una excepción:
// not throw an error:
$ this ->-> noThrowOnError ()-> insert ( ' id1 ' , ' values ' );
// but you can still see the latest error:
if ( $ this -> latestError ) {
var_dump ( $ this -> latestError );
}Puedes trabajar con CSV de la siguiente manera:
$ 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] no pudo cargar el paquete EFTEC/DocumentStoreOne en Repo.packagist.org: [inesperado ValueException] no pudo analizar la restricción de la versión ^5.6. : Cadena de versión no válida "^5.6".