From 1e413bb1ae1b55cf6908556f1507659886dfdd73 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Thu, 16 Aug 2018 23:18:53 -0400 Subject: [PATCH 01/51] =?UTF-8?q?Changed:=20#24=20=E2=80=93=20Array=20keys?= =?UTF-8?q?=20on=20query=20results()=20and=20resultDocuments()=20change=20?= =?UTF-8?q?indexes=20from=20chronological=20integers=20to=20document=20Id.?= =?UTF-8?q?=20Adding=20the=20ID=20within=20the=20array=20key=20allows=20a?= =?UTF-8?q?=20reference=20the=20original=20document.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 ++ README.md | 6 +-- src/Cache.php | 2 +- src/Database.php | 8 +-- src/Query.php | 2 +- src/QueryLogic.php | 6 +-- tests/DatabaseTest.php | 2 +- tests/QueryTest.php | 119 +++++++++++++++++++++++++++++++++-------- 8 files changed, 115 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a71e0a9..8826c0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Change Log ========== +### 08/16/2018 - 1.0.21 +* Changed: #24 – Array keys on query `results()` and `resultDocuments()` change indexes from chronological integers to document Id. Adding the ID within the array key allows a reference the original document. + +**NOTE** It is possible this *could* potentially break code. This will change query array indexes from `$myResults[0]` to `$myResults['my_document_id']`. + ### 08/16/2018 - 1.0.20 * Fixed #23 – Caching is cleared when deleting/saving documents to prevent cache from being out of sync with document data. diff --git a/README.md b/README.md index cffa27e..116792b 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Here is a list of methods you can use on the database class. |---|---| |`version()` | Current version of your Filebase library | |`get($id)` | Refer to [get()](https://github.com/filebase/Filebase#3-get-and-methods) | -|`has($id)` | Check if a record exist returning true/false | +|`has($id)` | Check if a record exist returning true/false (added: 1.0.19) | |`findAll()` | Returns all documents in database | |`count()` | Number of documents in database | |`flush(true)` | Deletes all documents. | @@ -405,8 +405,8 @@ The below **methods execute the query** and return results *(do not try to use t |`count()` | Counts and returns the number of documents in results. | |`first()` | Returns only the first document in results. | |`last()` | Returns only the last document in results. | -|`results()` | This will return all the documents found and their data as an array. Passing the argument of `false` will be the same as `resultDocuments()` (returning the full document objects) | -|`resultDocuments()` | This will return all the documents found and their data as document objects, or you can do `results(false)` which is the alias. | +|`results()` | This will return all the documents found and their data as an array. | +|`resultDocuments()` | This will return all the documents found and their data as document objects. | ### Comparison Operators: diff --git a/src/Cache.php b/src/Cache.php index 47090f3..212bd73 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -119,7 +119,7 @@ public function getDocuments($documents) $d = []; foreach($documents as $document) { - $d[] = $this->database->get($document)->setFromCache(true); + $d[$document] = $this->database->get($document)->setFromCache(true); } return $d; diff --git a/src/Database.php b/src/Database.php index 88f6ed0..eddd0f8 100644 --- a/src/Database.php +++ b/src/Database.php @@ -16,7 +16,7 @@ class Database * Stores the version of Filebase * use $db->getVersion() */ - const VERSION = '1.0.20'; + const VERSION = '1.0.21'; //-------------------------------------------------------------------- @@ -100,13 +100,15 @@ public function findAll($include_documents = true, $data_only = false) foreach($all_items as $a) { + $document = $this->get($a); + if ($data_only === true) { - $items[] = $this->get($a)->getData(); + $items[$document->getId()] = $document->getData(); } else { - $items[] = $this->get($a); + $items[$document->getId()] = $document; } } diff --git a/src/Query.php b/src/Query.php index 62869ac..f13558b 100644 --- a/src/Query.php +++ b/src/Query.php @@ -260,7 +260,7 @@ public function toArray() { foreach($this->documents as $document) { - $docs[] = (array) $document->getData(); + $docs[$document->getId()] = (array) $document->getData(); } } diff --git a/src/QueryLogic.php b/src/QueryLogic.php index 764e190..cac9982 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -71,7 +71,7 @@ public function run() if ($cached_documents = $this->cache->get()) { - $this->documents = $cached_documents; + $this->documents = ($cached_documents); $this->sort(); $this->offsetLimit(); @@ -141,7 +141,7 @@ protected function filter($documents, $predicates) { list($field, $operator, $value) = $predicate; - $documents = array_values(array_filter($documents, function ($document) use ($field, $operator, $value) { + $documents = (array_filter($documents, function ($document) use ($field, $operator, $value) { return $this->match($document, $field, $operator, $value); })); @@ -155,7 +155,7 @@ protected function filter($documents, $predicates) { list($field, $operator, $value) = $predicate; - $documents = array_values(array_filter($org_docs, function ($document) use ($field, $operator, $value) { + $documents = (array_filter($org_docs, function ($document) use ($field, $operator, $value) { return $this->match($document, $field, $operator, $value); })); diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index ddd6d7c..3ec0830 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -236,7 +236,7 @@ public function testDatabaseFindAllDataOnly() // should only have 1 doc $this->assertEquals(1, count($documents)); - $this->assertEquals(['key'=>'value'], $documents[0]); + $this->assertEquals(['key'=>'value'], current($documents)); $db->flush(true); } diff --git a/tests/QueryTest.php b/tests/QueryTest.php index c5a1db4..b162848 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -347,9 +347,11 @@ public function testLimitOffset() // test that the offset takes off the first array (should return "apple", not "google") $test3 = $db->query()->where('rank','=',150)->limit(1,1)->results(); + $test3Current = current($test3); + $this->assertEquals(2, (count($test1))); $this->assertEquals(3, (count($test2))); - $this->assertEquals('Apple', $test3[0]['name']); + $this->assertEquals('Apple', $test3Current['name']); $db->flush(true); } @@ -457,23 +459,38 @@ public function testSorting() // test that they are ordered by name ASC (check first, second, and last) $test1 = $db->query()->where('status','=','enabled')->orderBy('name', 'ASC')->results(); - $this->assertEquals(['first'=>'Amazon','second'=>'Amex','last'=>'Microsoft'], ['first'=>$test1[0]['name'],'second'=>$test1[1]['name'],'last'=>$test1[5]['name']]); + $test1A = current($test1); + $test1B = next($test1); + $test1C = end($test1); + $this->assertEquals(['first'=>'Amazon','second'=>'Amex','last'=>'Microsoft'], ['first'=>$test1A['name'],'second'=>$test1B['name'],'last'=>$test1C['name']]); // test that they are ordered by name ASC (check first, second, and last) $test2 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('name', 'ASC')->results(); - $this->assertEquals(['Amazon','Amex','Apple'], [$test2[0]['name'],$test2[1]['name'],$test2[2]['name']]); + $testA = current($test2); + $testB = next($test2); + $testC = end($test2); + $this->assertEquals(['Amazon','Amex','Apple'], [$testA['name'],$testB['name'],$testC['name']]); // test that they are ordered by name DESC (check first, second, and last) $test3 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('name', 'DESC')->results(); - $this->assertEquals(['Microsoft','Hooli','Google'], [$test3[0]['name'],$test3[1]['name'],$test3[2]['name']]); + $testA = current($test3); + $testB = next($test3); + $testC = end($test3); + $this->assertEquals(['Microsoft','Hooli','Google'], [$testA['name'],$testB['name'],$testC['name']]); // test that they are ordered by rank nested [reviews] DESC $test4 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('rank.reviews', 'DESC')->results(); - $this->assertEquals(['Apple','Google','Amazon'], [$test4[0]['name'],$test4[1]['name'],$test4[2]['name']]); + $testA = current($test4); + $testB = next($test4); + $testC = end($test4); + $this->assertEquals(['Apple','Google','Amazon'], [$testA['name'],$testB['name'],$testC['name']]); // test that they are ordered by rank nested [reviews] ASC $test5 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('rank.reviews', 'ASC')->results(); - $this->assertEquals(['Amex','Hooli','Microsoft'], [$test5[0]['name'],$test5[1]['name'],$test5[2]['name']]); + $testA = current($test5); + $testB = next($test5); + $testC = end($test5); + $this->assertEquals(['Amex','Hooli','Microsoft'], [$testA['name'],$testB['name'],$testC['name']]); $db->flush(true); @@ -488,11 +505,17 @@ public function testSorting() // order the results ASC (but inject numbers into strings) $test6 = $db->query()->limit(3)->orderBy('name', 'ASC')->results(); - $this->assertEquals(['Google 1','Google 2','Google 3'], [$test6[0]['name'],$test6[1]['name'],$test6[2]['name']]); + $testA = current($test6); + $testB = next($test6); + $testC = end($test6); + $this->assertEquals(['Google 1','Google 2','Google 3'], [$testA['name'],$testB['name'],$testC['name']]); // order the results DESC (but inject numbers into strings) $test6 = $db->query()->limit(3)->orderBy('name', 'DESC')->results(); - $this->assertEquals(['Google 10','Google 9','Google 7'], [$test6[0]['name'],$test6[1]['name'],$test6[2]['name']]); + $testA = current($test6); + $testB = next($test6); + $testC = end($test6); + $this->assertEquals(['Google 10','Google 9','Google 7'], [$testA['name'],$testB['name'],$testC['name']]); $db->flush(true); @@ -562,8 +585,8 @@ public function testWhereIn() $this->assertEquals('Microsoft', $test3['name']); // check if the method createdAt() exists or not based on the argument boolean - $this->assertEquals(true, method_exists($test5[0], 'createdAt')); - $this->assertEquals(false, method_exists($test6[0], 'createdAt')); + $this->assertEquals(true, method_exists(current($test5), 'createdAt')); + $this->assertEquals(false, method_exists(current($test6), 'createdAt')); // check if the results = 2 $this->assertEquals(2, count($test4)); @@ -956,8 +979,10 @@ public function testWhereQueryFromCache() ->andWhere('email','==','john@example.com') ->resultDocuments(); + $first = current($result_from_cache); + $this->assertEquals(10, count($results)); - $this->assertEquals(true, ($result_from_cache[0]->isCache())); + $this->assertEquals(true, ($first->isCache())); $db->flush(true); } @@ -983,21 +1008,24 @@ public function testQueryFromCacheAfterDelete() $results = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); $result_from_cache = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + $current = current($result_from_cache); + $this->assertEquals(10, count($results)); - $this->assertEquals(true, ($result_from_cache[0]->isCache())); + $this->assertEquals(10, count($result_from_cache)); + $this->assertEquals(true, $current->isCache()); - $id = $result_from_cache[0]->getId(); - $id2 = $result_from_cache[1]->getId(); + $id = $current->getId(); + $id2 = next($result_from_cache)->getId(); // delete the file - $result_from_cache[0]->delete(); + $current->delete(); $results = $db->query() ->where('name','=','John') ->andWhere('email','==','john@example.com') ->resultDocuments(); - $this->assertEquals($id2, $results[0]->getId()); + $this->assertEquals($id2, current($results)->getId()); $db->flush(true); } @@ -1024,25 +1052,70 @@ public function testQueryFromCacheAfterSave() $results = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); $result_from_cache = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + $current = current($result_from_cache); + $this->assertEquals(10, count($results)); - $this->assertEquals(true, ($result_from_cache[0]->isCache())); + $this->assertEquals(10, count($result_from_cache)); + $this->assertEquals(true, $current->isCache()); - $id = $result_from_cache[0]->getId(); - $id2 = $result_from_cache[1]->getId(); + $id = $current->getId(); + $id2 = next($result_from_cache)->getId(); // Change the name - $result_from_cache[0]->name = 'Tim'; - $result_from_cache[0]->save(); + $current->name = 'Tim'; + $current->save(); $results = $db->query() ->where('name','=','John') ->andWhere('email','==','john@example.com') ->resultDocuments(); - $this->assertEquals($id2, $results[0]->getId()); - $this->assertEquals('John', $results[0]->name); + $this->assertEquals($id2, current($results)->getId()); + $this->assertEquals('John', current($results)->name); + + $db->flush(true); + } + + + public function testQueryResultKeys() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/results', + 'cache' => true + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->save(); + } + + $resultsA = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results(); + $resultsB = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results(); + + $this->assertEquals($resultsB, $resultsA); + + $db->flushCache(); + $resultsC = current($db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results()); + $db->flushCache(); + $resultsD = current($db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results()); + + $this->assertEquals($resultsC, $resultsD); + + $db->flushCache(); + $resultsE = current($db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments()); + $db->flushCache(); + $resultsF = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + + $this->assertEquals($resultsB[$resultsE->getId()], $resultsE->getData()); + $this->assertEquals($resultsF[$resultsE->getId()]->getData(), $resultsE->getData()); $db->flush(true); + $db->flushCache(); } } From a05fc65a565cad16759b6e3e88c721f7b91cab32 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Thu, 16 Aug 2018 23:25:53 -0400 Subject: [PATCH 02/51] Fixing php5.6 test on query. --- tests/QueryTest.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/QueryTest.php b/tests/QueryTest.php index b162848..30a3e0c 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1025,7 +1025,9 @@ public function testQueryFromCacheAfterDelete() ->andWhere('email','==','john@example.com') ->resultDocuments(); - $this->assertEquals($id2, current($results)->getId()); + $r = current($results); + + $this->assertEquals($id2, $r->getId()); $db->flush(true); } @@ -1070,8 +1072,10 @@ public function testQueryFromCacheAfterSave() ->andWhere('email','==','john@example.com') ->resultDocuments(); - $this->assertEquals($id2, current($results)->getId()); - $this->assertEquals('John', current($results)->name); + $r = current($results); + + $this->assertEquals($id2, $r->getId()); + $this->assertEquals('John', $r->name); $db->flush(true); } From 3d34748d1de40b6f7b0238a5349b993ae1dd235a Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Thu, 16 Aug 2018 23:37:03 -0400 Subject: [PATCH 03/51] Revert "Fixing php5.6 test on query." This reverts commit a05fc65a565cad16759b6e3e88c721f7b91cab32. --- tests/QueryTest.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/QueryTest.php b/tests/QueryTest.php index 30a3e0c..b162848 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1025,9 +1025,7 @@ public function testQueryFromCacheAfterDelete() ->andWhere('email','==','john@example.com') ->resultDocuments(); - $r = current($results); - - $this->assertEquals($id2, $r->getId()); + $this->assertEquals($id2, current($results)->getId()); $db->flush(true); } @@ -1072,10 +1070,8 @@ public function testQueryFromCacheAfterSave() ->andWhere('email','==','john@example.com') ->resultDocuments(); - $r = current($results); - - $this->assertEquals($id2, $r->getId()); - $this->assertEquals('John', $r->name); + $this->assertEquals($id2, current($results)->getId()); + $this->assertEquals('John', current($results)->name); $db->flush(true); } From 4b17ceeb3da4ac8b70af8f98cc58437cf887e2d3 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Thu, 16 Aug 2018 23:37:11 -0400 Subject: [PATCH 04/51] =?UTF-8?q?Revert=20"Changed:=20#24=20=E2=80=93=20Ar?= =?UTF-8?q?ray=20keys=20on=20query=20results()=20and=20resultDocuments()?= =?UTF-8?q?=20change=20indexes=20from=20chronological=20integers=20to=20do?= =?UTF-8?q?cument=20Id.=20Adding=20the=20ID=20within=20the=20array=20key?= =?UTF-8?q?=20allows=20a=20reference=20the=20original=20document."?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1e413bb1ae1b55cf6908556f1507659886dfdd73. --- CHANGELOG.md | 5 -- README.md | 6 +-- src/Cache.php | 2 +- src/Database.php | 8 ++- src/Query.php | 2 +- src/QueryLogic.php | 6 +-- tests/DatabaseTest.php | 2 +- tests/QueryTest.php | 119 ++++++++--------------------------------- 8 files changed, 35 insertions(+), 115 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8826c0e..a71e0a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,6 @@ Change Log ========== -### 08/16/2018 - 1.0.21 -* Changed: #24 – Array keys on query `results()` and `resultDocuments()` change indexes from chronological integers to document Id. Adding the ID within the array key allows a reference the original document. - -**NOTE** It is possible this *could* potentially break code. This will change query array indexes from `$myResults[0]` to `$myResults['my_document_id']`. - ### 08/16/2018 - 1.0.20 * Fixed #23 – Caching is cleared when deleting/saving documents to prevent cache from being out of sync with document data. diff --git a/README.md b/README.md index 116792b..cffa27e 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ Here is a list of methods you can use on the database class. |---|---| |`version()` | Current version of your Filebase library | |`get($id)` | Refer to [get()](https://github.com/filebase/Filebase#3-get-and-methods) | -|`has($id)` | Check if a record exist returning true/false (added: 1.0.19) | +|`has($id)` | Check if a record exist returning true/false | |`findAll()` | Returns all documents in database | |`count()` | Number of documents in database | |`flush(true)` | Deletes all documents. | @@ -405,8 +405,8 @@ The below **methods execute the query** and return results *(do not try to use t |`count()` | Counts and returns the number of documents in results. | |`first()` | Returns only the first document in results. | |`last()` | Returns only the last document in results. | -|`results()` | This will return all the documents found and their data as an array. | -|`resultDocuments()` | This will return all the documents found and their data as document objects. | +|`results()` | This will return all the documents found and their data as an array. Passing the argument of `false` will be the same as `resultDocuments()` (returning the full document objects) | +|`resultDocuments()` | This will return all the documents found and their data as document objects, or you can do `results(false)` which is the alias. | ### Comparison Operators: diff --git a/src/Cache.php b/src/Cache.php index 212bd73..47090f3 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -119,7 +119,7 @@ public function getDocuments($documents) $d = []; foreach($documents as $document) { - $d[$document] = $this->database->get($document)->setFromCache(true); + $d[] = $this->database->get($document)->setFromCache(true); } return $d; diff --git a/src/Database.php b/src/Database.php index eddd0f8..88f6ed0 100644 --- a/src/Database.php +++ b/src/Database.php @@ -16,7 +16,7 @@ class Database * Stores the version of Filebase * use $db->getVersion() */ - const VERSION = '1.0.21'; + const VERSION = '1.0.20'; //-------------------------------------------------------------------- @@ -100,15 +100,13 @@ public function findAll($include_documents = true, $data_only = false) foreach($all_items as $a) { - $document = $this->get($a); - if ($data_only === true) { - $items[$document->getId()] = $document->getData(); + $items[] = $this->get($a)->getData(); } else { - $items[$document->getId()] = $document; + $items[] = $this->get($a); } } diff --git a/src/Query.php b/src/Query.php index f13558b..62869ac 100644 --- a/src/Query.php +++ b/src/Query.php @@ -260,7 +260,7 @@ public function toArray() { foreach($this->documents as $document) { - $docs[$document->getId()] = (array) $document->getData(); + $docs[] = (array) $document->getData(); } } diff --git a/src/QueryLogic.php b/src/QueryLogic.php index cac9982..764e190 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -71,7 +71,7 @@ public function run() if ($cached_documents = $this->cache->get()) { - $this->documents = ($cached_documents); + $this->documents = $cached_documents; $this->sort(); $this->offsetLimit(); @@ -141,7 +141,7 @@ protected function filter($documents, $predicates) { list($field, $operator, $value) = $predicate; - $documents = (array_filter($documents, function ($document) use ($field, $operator, $value) { + $documents = array_values(array_filter($documents, function ($document) use ($field, $operator, $value) { return $this->match($document, $field, $operator, $value); })); @@ -155,7 +155,7 @@ protected function filter($documents, $predicates) { list($field, $operator, $value) = $predicate; - $documents = (array_filter($org_docs, function ($document) use ($field, $operator, $value) { + $documents = array_values(array_filter($org_docs, function ($document) use ($field, $operator, $value) { return $this->match($document, $field, $operator, $value); })); diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 3ec0830..ddd6d7c 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -236,7 +236,7 @@ public function testDatabaseFindAllDataOnly() // should only have 1 doc $this->assertEquals(1, count($documents)); - $this->assertEquals(['key'=>'value'], current($documents)); + $this->assertEquals(['key'=>'value'], $documents[0]); $db->flush(true); } diff --git a/tests/QueryTest.php b/tests/QueryTest.php index b162848..c5a1db4 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -347,11 +347,9 @@ public function testLimitOffset() // test that the offset takes off the first array (should return "apple", not "google") $test3 = $db->query()->where('rank','=',150)->limit(1,1)->results(); - $test3Current = current($test3); - $this->assertEquals(2, (count($test1))); $this->assertEquals(3, (count($test2))); - $this->assertEquals('Apple', $test3Current['name']); + $this->assertEquals('Apple', $test3[0]['name']); $db->flush(true); } @@ -459,38 +457,23 @@ public function testSorting() // test that they are ordered by name ASC (check first, second, and last) $test1 = $db->query()->where('status','=','enabled')->orderBy('name', 'ASC')->results(); - $test1A = current($test1); - $test1B = next($test1); - $test1C = end($test1); - $this->assertEquals(['first'=>'Amazon','second'=>'Amex','last'=>'Microsoft'], ['first'=>$test1A['name'],'second'=>$test1B['name'],'last'=>$test1C['name']]); + $this->assertEquals(['first'=>'Amazon','second'=>'Amex','last'=>'Microsoft'], ['first'=>$test1[0]['name'],'second'=>$test1[1]['name'],'last'=>$test1[5]['name']]); // test that they are ordered by name ASC (check first, second, and last) $test2 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('name', 'ASC')->results(); - $testA = current($test2); - $testB = next($test2); - $testC = end($test2); - $this->assertEquals(['Amazon','Amex','Apple'], [$testA['name'],$testB['name'],$testC['name']]); + $this->assertEquals(['Amazon','Amex','Apple'], [$test2[0]['name'],$test2[1]['name'],$test2[2]['name']]); // test that they are ordered by name DESC (check first, second, and last) $test3 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('name', 'DESC')->results(); - $testA = current($test3); - $testB = next($test3); - $testC = end($test3); - $this->assertEquals(['Microsoft','Hooli','Google'], [$testA['name'],$testB['name'],$testC['name']]); + $this->assertEquals(['Microsoft','Hooli','Google'], [$test3[0]['name'],$test3[1]['name'],$test3[2]['name']]); // test that they are ordered by rank nested [reviews] DESC $test4 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('rank.reviews', 'DESC')->results(); - $testA = current($test4); - $testB = next($test4); - $testC = end($test4); - $this->assertEquals(['Apple','Google','Amazon'], [$testA['name'],$testB['name'],$testC['name']]); + $this->assertEquals(['Apple','Google','Amazon'], [$test4[0]['name'],$test4[1]['name'],$test4[2]['name']]); // test that they are ordered by rank nested [reviews] ASC $test5 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('rank.reviews', 'ASC')->results(); - $testA = current($test5); - $testB = next($test5); - $testC = end($test5); - $this->assertEquals(['Amex','Hooli','Microsoft'], [$testA['name'],$testB['name'],$testC['name']]); + $this->assertEquals(['Amex','Hooli','Microsoft'], [$test5[0]['name'],$test5[1]['name'],$test5[2]['name']]); $db->flush(true); @@ -505,17 +488,11 @@ public function testSorting() // order the results ASC (but inject numbers into strings) $test6 = $db->query()->limit(3)->orderBy('name', 'ASC')->results(); - $testA = current($test6); - $testB = next($test6); - $testC = end($test6); - $this->assertEquals(['Google 1','Google 2','Google 3'], [$testA['name'],$testB['name'],$testC['name']]); + $this->assertEquals(['Google 1','Google 2','Google 3'], [$test6[0]['name'],$test6[1]['name'],$test6[2]['name']]); // order the results DESC (but inject numbers into strings) $test6 = $db->query()->limit(3)->orderBy('name', 'DESC')->results(); - $testA = current($test6); - $testB = next($test6); - $testC = end($test6); - $this->assertEquals(['Google 10','Google 9','Google 7'], [$testA['name'],$testB['name'],$testC['name']]); + $this->assertEquals(['Google 10','Google 9','Google 7'], [$test6[0]['name'],$test6[1]['name'],$test6[2]['name']]); $db->flush(true); @@ -585,8 +562,8 @@ public function testWhereIn() $this->assertEquals('Microsoft', $test3['name']); // check if the method createdAt() exists or not based on the argument boolean - $this->assertEquals(true, method_exists(current($test5), 'createdAt')); - $this->assertEquals(false, method_exists(current($test6), 'createdAt')); + $this->assertEquals(true, method_exists($test5[0], 'createdAt')); + $this->assertEquals(false, method_exists($test6[0], 'createdAt')); // check if the results = 2 $this->assertEquals(2, count($test4)); @@ -979,10 +956,8 @@ public function testWhereQueryFromCache() ->andWhere('email','==','john@example.com') ->resultDocuments(); - $first = current($result_from_cache); - $this->assertEquals(10, count($results)); - $this->assertEquals(true, ($first->isCache())); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); $db->flush(true); } @@ -1008,24 +983,21 @@ public function testQueryFromCacheAfterDelete() $results = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); $result_from_cache = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); - $current = current($result_from_cache); - $this->assertEquals(10, count($results)); - $this->assertEquals(10, count($result_from_cache)); - $this->assertEquals(true, $current->isCache()); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); - $id = $current->getId(); - $id2 = next($result_from_cache)->getId(); + $id = $result_from_cache[0]->getId(); + $id2 = $result_from_cache[1]->getId(); // delete the file - $current->delete(); + $result_from_cache[0]->delete(); $results = $db->query() ->where('name','=','John') ->andWhere('email','==','john@example.com') ->resultDocuments(); - $this->assertEquals($id2, current($results)->getId()); + $this->assertEquals($id2, $results[0]->getId()); $db->flush(true); } @@ -1052,70 +1024,25 @@ public function testQueryFromCacheAfterSave() $results = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); $result_from_cache = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); - $current = current($result_from_cache); - $this->assertEquals(10, count($results)); - $this->assertEquals(10, count($result_from_cache)); - $this->assertEquals(true, $current->isCache()); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); - $id = $current->getId(); - $id2 = next($result_from_cache)->getId(); + $id = $result_from_cache[0]->getId(); + $id2 = $result_from_cache[1]->getId(); // Change the name - $current->name = 'Tim'; - $current->save(); + $result_from_cache[0]->name = 'Tim'; + $result_from_cache[0]->save(); $results = $db->query() ->where('name','=','John') ->andWhere('email','==','john@example.com') ->resultDocuments(); - $this->assertEquals($id2, current($results)->getId()); - $this->assertEquals('John', current($results)->name); - - $db->flush(true); - } - - - public function testQueryResultKeys() - { - $db = new \Filebase\Database([ - 'dir' => __DIR__.'/databases/results', - 'cache' => true - ]); - - $db->flush(true); - - for ($x = 1; $x <= 10; $x++) - { - $user = $db->get(uniqid()); - $user->name = 'John'; - $user->email = 'john@example.com'; - $user->save(); - } - - $resultsA = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results(); - $resultsB = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results(); - - $this->assertEquals($resultsB, $resultsA); - - $db->flushCache(); - $resultsC = current($db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results()); - $db->flushCache(); - $resultsD = current($db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->results()); - - $this->assertEquals($resultsC, $resultsD); - - $db->flushCache(); - $resultsE = current($db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments()); - $db->flushCache(); - $resultsF = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); - - $this->assertEquals($resultsB[$resultsE->getId()], $resultsE->getData()); - $this->assertEquals($resultsF[$resultsE->getId()]->getData(), $resultsE->getData()); + $this->assertEquals($id2, $results[0]->getId()); + $this->assertEquals('John', $results[0]->name); $db->flush(true); - $db->flushCache(); } } From 1041acaf2e781b0fd7c0f8ecf9a33715ab04a42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=BDold=C3=A1k?= Date: Tue, 28 Aug 2018 18:07:57 +0200 Subject: [PATCH 05/51] Json format: refactor error handling + add JSON_UNESCAPED_UNICODE --- src/Database.php | 35 ++++++++++++++++----- src/Format/DecodingException.php | 6 ++++ src/Format/EncodingException.php | 6 ++++ src/Format/FormatException.php | 18 +++++++++++ src/Format/Json.php | 54 +++++++++++++++++++++++--------- 5 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 src/Format/DecodingException.php create mode 100644 src/Format/EncodingException.php create mode 100644 src/Format/FormatException.php diff --git a/src/Database.php b/src/Database.php index 88f6ed0..32a5bdd 100644 --- a/src/Database.php +++ b/src/Database.php @@ -6,6 +6,8 @@ use Filebase\Filesystem; use Filebase\Document; use Filebase\Backup; +use Filebase\Format\DecodingException; +use Filebase\Format\EncodingException; class Database { @@ -270,7 +272,11 @@ public function save(Document $document, $wdata = '') $document->setUpdatedAt(time()); - $data = $format::encode( $document->saveAs(), $this->config->pretty ); + try { + $data = $format::encode( $document->saveAs(), $this->config->pretty ); + } catch (EncodingException $e) { + // TODO: handle exception: log?, throw write exception?... + } if (Filesystem::write($file_location, $data)) { @@ -302,17 +308,30 @@ public function query() //-------------------------------------------------------------------- - /** - * read - * - * @param string $name - * @return decoded file data - */ + * @param $name + * @return bool + * @throws Exception + */ protected function read($name) { $format = $this->config->format; - return $format::decode( Filesystem::read( $this->config->dir.'/'.Filesystem::validateName($name, $this->config->safe_filename).'.'.$format::getFileExtension() ) ); + + $file = Filesystem::read( + $this->config->dir . '/' + . Filesystem::validateName($name, $this->config->safe_filename) + . '.' . $format::getFileExtension() + ); + + if ($file) { + try { + return $format::decode($file); + } catch (DecodingException $e) { + // TODO: handle exception: log?, throw read exception?... + } + } + + return false; } diff --git a/src/Format/DecodingException.php b/src/Format/DecodingException.php new file mode 100644 index 0000000..bcb7de2 --- /dev/null +++ b/src/Format/DecodingException.php @@ -0,0 +1,6 @@ +inputData = $inputData; + } + + public function getInputData() + { + return $this->inputData; + } +} + diff --git a/src/Format/Json.php b/src/Format/Json.php index 98071a9..337ed38 100644 --- a/src/Format/Json.php +++ b/src/Format/Json.php @@ -3,11 +3,9 @@ class Json implements FormatInterface { - /** - * getFileExtension - * - */ + * @return string + */ public static function getFileExtension() { return 'json'; @@ -18,15 +16,29 @@ public static function getFileExtension() /** - * encode - * - */ + * @param array $data + * @param bool $pretty + * @return string + * @throws FormatException + */ public static function encode($data = [], $pretty = true) { - $p = 1; - if ($pretty==true) $p = JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES; - - return json_encode($data, $p); + $options = 0; + if ($pretty == true) { + $options = JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE; + } + + $encoded = json_encode($data, $options); + if ($encoded === false) { + throw new EncodingException( + "json_encode: '" . json_last_error_msg() . "'", + 0, + null, + $data + ); + } + + return $encoded; } @@ -34,12 +46,24 @@ public static function encode($data = [], $pretty = true) /** - * decode - * - */ + * @param $data + * @return mixed + * @throws FormatException + */ public static function decode($data) { - return json_decode($data, 1); + $decoded = json_decode($data, true); + + if ($data !== false && $decoded === null) { + throw new DecodingException( + "json_decode: '" . json_last_error_msg() . "'", + 0, + null, + $data + ); + } + + return $decoded; } From f3f0b2562edef7bf31b56411d73d90c8de7a3055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=BDold=C3=A1k?= Date: Tue, 28 Aug 2018 21:19:26 +0200 Subject: [PATCH 06/51] add & use Filesystem exceptions + test not encodable document --- src/Database.php | 40 ++++++++++++++++---------- src/Filesystem/FilesystemException.php | 6 ++++ src/Filesystem/ReadingException.php | 6 ++++ src/Filesystem/SavingException.php | 6 ++++ tests/DatabaseTest.php | 17 +++++++++++ 5 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 src/Filesystem/FilesystemException.php create mode 100644 src/Filesystem/ReadingException.php create mode 100644 src/Filesystem/SavingException.php diff --git a/src/Database.php b/src/Database.php index 32a5bdd..45b92e5 100644 --- a/src/Database.php +++ b/src/Database.php @@ -8,6 +8,9 @@ use Filebase\Backup; use Filebase\Format\DecodingException; use Filebase\Format\EncodingException; +use Filebase\Filesystem\SavingException; +use Filebase\Filesystem\ReadingException; +use Filebase\Filesystem\FilesystemException; class Database { @@ -33,9 +36,12 @@ class Database /** - * __construct - * - */ + * Database constructor. + * + * @param array $config + * + * @throws FilesystemException + */ public function __construct(array $config = []) { $this->config = new Config($config); @@ -48,12 +54,12 @@ public function __construct(array $config = []) { if (!@mkdir($this->config->dir, 0777, true)) { - throw new Exception(sprintf('`%s` doesn\'t exist and can\'t be created.', $this->config->dir)); + throw new FilesystemException(sprintf('`%s` doesn\'t exist and can\'t be created.', $this->config->dir)); } } else if (!is_writable($this->config->dir)) { - throw new Exception(sprintf('`%s` is not writable.', $this->config->dir)); + throw new FilesystemException(sprintf('`%s` is not writable.', $this->config->dir)); } } @@ -242,13 +248,14 @@ public function count() * @param $document \Filebase\Document object * @param mixed $data should be an array, new data to replace all existing data within * + * @throws Exception|SavingException * @return (bool) true or false if file was saved */ public function save(Document $document, $wdata = '') { if ($this->config->read_only === true) { - throw new Exception("This database is set to be read-only. No modifications can be made."); + throw new SavingException("This database is set to be read-only. No modifications can be made."); } $format = $this->config->format; @@ -275,7 +282,8 @@ public function save(Document $document, $wdata = '') try { $data = $format::encode( $document->saveAs(), $this->config->pretty ); } catch (EncodingException $e) { - // TODO: handle exception: log?, throw write exception?... + // TODO: add logging + throw new SavingException("Can not encode document.", 0, $e); } if (Filesystem::write($file_location, $data)) @@ -311,7 +319,7 @@ public function query() /** * @param $name * @return bool - * @throws Exception + * @throws Exception|ReadingException */ protected function read($name) { @@ -323,15 +331,17 @@ protected function read($name) . '.' . $format::getFileExtension() ); - if ($file) { - try { - return $format::decode($file); - } catch (DecodingException $e) { - // TODO: handle exception: log?, throw read exception?... - } + if (!$file) { + /** + * FIXME: shouldn't we raise an exception in this case? + implement add/create method? + * or use $this->has (maybe not here but inside $this->get method) to verify that document exists + * if not than use add/create method? + * or remove this exception and allow creating new document with this method? + */ +// throw new ReadingException("Document '{$name}' does not exists."); } - return false; + return $format::decode($file); } diff --git a/src/Filesystem/FilesystemException.php b/src/Filesystem/FilesystemException.php new file mode 100644 index 0000000..f901aba --- /dev/null +++ b/src/Filesystem/FilesystemException.php @@ -0,0 +1,6 @@ +flush(true); } + public function testDatabaseSavingNotEncodableDocument() + { + $this->expectException(SavingException::class); + + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases' + ]); + + $doc = $db->get("testDatabaseSavingNotEncodableDocument"); + + // insert invalid utf-8 characters + $doc->testProp = "\xB1\x31"; + + $doc->save(); + } } From d0774edf3cb830eff1d783d4f81e811e0ee72b12 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Tue, 28 Aug 2018 19:37:52 -0400 Subject: [PATCH 07/51] Updated readme [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cffa27e..03b64d9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Filebase -[![Build Status](https://travis-ci.org/filebase/Filebase.svg?branch=1.0)](https://travis-ci.org/filebase/Filebase) [![Coverage Status](https://coveralls.io/repos/github/filebase/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/filebase/Filebase?branch=1.0) +[![Build Status](https://travis-ci.org/filebase/Filebase.svg?branch=1.0)](https://travis-ci.org/filebase/Filebase) [![Coverage Status](https://coveralls.io/repos/github/filebase/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/filebase/Filebase?branch=1.0) [![Slack](http://timothymarois.com/a/slack-01.svg)](https://join.slack.com/t/basephp/shared_invite/enQtNDI0MzQyMDE0MDAwLWU3Nzg0Yjk4MjM0OWVmZDZjMjEyYWE2YjA1ODFhNjI2MzI3MjAyOTIyOTRkMmVlNWNhZWYzMTIwZDJlOWQ2ZTA) A Simple but Powerful Flat File Database Storage. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](https://github.com/filebase/Filebase#2-formatting) the way you like). From 47ec1f9fc9d8bf5349ade6d6d4c4248310f7f7eb Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Tue, 28 Aug 2018 19:48:14 -0400 Subject: [PATCH 08/51] Updated readme --- README.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 03b64d9..3c63f22 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Filebase -[![Build Status](https://travis-ci.org/filebase/Filebase.svg?branch=1.0)](https://travis-ci.org/filebase/Filebase) [![Coverage Status](https://coveralls.io/repos/github/filebase/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/filebase/Filebase?branch=1.0) [![Slack](http://timothymarois.com/a/slack-01.svg)](https://join.slack.com/t/basephp/shared_invite/enQtNDI0MzQyMDE0MDAwLWU3Nzg0Yjk4MjM0OWVmZDZjMjEyYWE2YjA1ODFhNjI2MzI3MjAyOTIyOTRkMmVlNWNhZWYzMTIwZDJlOWQ2ZTA) +[![Build Status](https://travis-ci.org/filebase/Filebase.svg?branch=1.0)](https://travis-ci.org/filebase/Filebase) [![Coverage Status](https://coveralls.io/repos/github/filebase/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/filebase/Filebase?branch=1.0) [![Slack](http://timothymarois.com/a/slack-02.svg)](https://join.slack.com/t/basephp/shared_invite/enQtNDI0MzQyMDE0MDAwLWU3Nzg0Yjk4MjM0OWVmZDZjMjEyYWE2YjA1ODFhNjI2MzI3MjAyOTIyOTRkMmVlNWNhZWYzMTIwZDJlOWQ2ZTA) A Simple but Powerful Flat File Database Storage. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](https://github.com/filebase/Filebase#2-formatting) the way you like). @@ -32,7 +32,7 @@ Filebase is simple by design, but has enough features for the more advanced. Use [Composer](http://getcomposer.org/) to install package. -Use `composer require filebase/filebase` +Run `composer require filebase/filebase` If you do not want to use composer, download the files, and include it within your application, it does not have any dependencies, you will just need to keep it updated with any future releases. @@ -470,7 +470,7 @@ $database->backup()->rollback(); ## Why Filebase? -I originally built Filebase because I needed more flexibility, control over the database files, how they are stored, query filtration and a design with very intuitive API methods. +Filebase was built for the flexibility to help manage simple data storage without the hassle of a heavy database engine. The concept of Filebase is to provide very intuitive API methods, and make it easy for the developer to maintain and manage (even on a large scale). Inspired by [Flywheel](https://github.com/jamesmoss/flywheel) and [Flinetone](https://github.com/fire015/flintstone). @@ -483,6 +483,8 @@ Versions are as follows: Major.Minor.Patch * Minor: New Features/Changes that breaks compatibility. * Patch: New Features/Fixes that does not break compatibility. +Filebase will work hard to be backwards-compatible when possible. + ## Sites and Users of Filebase @@ -496,9 +498,14 @@ Versions are as follows: Major.Minor.Patch * [Discount Savings](https://discount-savings.com) * [Vivint - Smart Homes](http://smarthomesecurityplans.com/) -*If you are using Filebase on your website, send in a pull request and we will put your site up here.* +*If you are using Filebase on your website, send in a pull request and we will add your project here.* ## Contributions -Accepting contributions and feedback. Send in any issues and pull requests. +Anyone can contribute to Filebase. Please do so by posting issues when you've found something that is unexpected or sending a pull request for improvements. + + +## License + +BasePHP is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). From 45907afa094487b53bfc3c0cdb3e6e4e3232cab5 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Tue, 28 Aug 2018 19:58:21 -0400 Subject: [PATCH 09/51] Updated readme [ci skip] --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3c63f22..6c03d60 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,8 @@ The Default Format Class: `JSON` After you've loaded up your database config, then you can use the `get()` method to retrieve a single document of data. +If document does not exist, it will create a empty object for you to store data into. You can then call the `save()` method and it will create the document (or update an existing one). + ```php // my user id $userId = '92832711'; @@ -468,6 +470,7 @@ $database->backup()->rollback(); ``` + ## Why Filebase? Filebase was built for the flexibility to help manage simple data storage without the hassle of a heavy database engine. The concept of Filebase is to provide very intuitive API methods, and make it easy for the developer to maintain and manage (even on a large scale). @@ -483,7 +486,7 @@ Versions are as follows: Major.Minor.Patch * Minor: New Features/Changes that breaks compatibility. * Patch: New Features/Fixes that does not break compatibility. -Filebase will work hard to be backwards-compatible when possible. +Filebase will work-hard to be **backwards-compatible** when possible. ## Sites and Users of Filebase @@ -498,7 +501,7 @@ Filebase will work hard to be backwards-compatible when possible. * [Discount Savings](https://discount-savings.com) * [Vivint - Smart Homes](http://smarthomesecurityplans.com/) -*If you are using Filebase on your website, send in a pull request and we will add your project here.* +*If you are using Filebase – send in a pull request and we will add your project here.* ## Contributions @@ -508,4 +511,4 @@ Anyone can contribute to Filebase. Please do so by posting issues when you've fo ## License -BasePHP is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +Filebase is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). From b6a4e50995c2ed83a54f23001c6ed270077efc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=BDold=C3=A1k?= Date: Mon, 3 Sep 2018 18:22:42 +0200 Subject: [PATCH 10/51] test format json --- src/Database.php | 37 +++++++++++++----------------------- tests/FormatJsonTest.php | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 24 deletions(-) create mode 100644 tests/FormatJsonTest.php diff --git a/src/Database.php b/src/Database.php index 45b92e5..f6dcdfe 100644 --- a/src/Database.php +++ b/src/Database.php @@ -1,12 +1,6 @@ config->read_only === true) @@ -317,9 +308,13 @@ public function query() /** + * Read and return Document from filesystem by name. + * If doesn't exists return new empty Document. + * * @param $name - * @return bool + * * @throws Exception|ReadingException + * @return array|null */ protected function read($name) { @@ -331,17 +326,11 @@ protected function read($name) . '.' . $format::getFileExtension() ); - if (!$file) { - /** - * FIXME: shouldn't we raise an exception in this case? + implement add/create method? - * or use $this->has (maybe not here but inside $this->get method) to verify that document exists - * if not than use add/create method? - * or remove this exception and allow creating new document with this method? - */ -// throw new ReadingException("Document '{$name}' does not exists."); + if ($file !== false) { + return $format::decode($file); } - return $format::decode($file); + return null; } diff --git a/tests/FormatJsonTest.php b/tests/FormatJsonTest.php new file mode 100644 index 0000000..08e08fb --- /dev/null +++ b/tests/FormatJsonTest.php @@ -0,0 +1,41 @@ + 'timothy-m_arois', + 'email' => 'email@email.com' + ]; + + $json = Json::encode($data, false); + $testData = Json::decode($json); + + $this->assertEquals($data, $testData); + } + + public function testFormatJsonEncodeThrowsExceptionIfNotEncodable() + { + $this->expectException(EncodingException::class); + + $data = [ + 'invalid' => chr(193) + ]; + + Json::encode($data); + } + + public function testFormatJsonDecodeThrowsExceptionOnNotValidJson() + { + $this->expectException(DecodingException::class); + + $json = '{ invalid: "json"'; + + Json::decode($json); + } +} \ No newline at end of file From 3e2a65c0f8c1519f310810ad774143687a05ffa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=BDold=C3=A1k?= Date: Mon, 3 Sep 2018 18:31:06 +0200 Subject: [PATCH 11/51] update readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cffa27e..c1e2c1f 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,8 @@ $database = new \Filebase\Database([ ]); // in this example, you would search an exact user name -// It would technically be stored as user_name.json in the directories +// it would technically be stored as user_name.json in the directories +// if user_name.json doesn't exists get will return new empty Document $item = $database->get('kingslayer'); // display property values From 83f864d64de784ac8907322bb77f594dd02fa11b Mon Sep 17 00:00:00 2001 From: Jannis Rondorf Date: Wed, 19 Sep 2018 22:51:12 +0200 Subject: [PATCH 12/51] Add Yaml format --- README.md | 4 + composer.json | 9 +- src/Format/Yaml.php | 50 ++ tests/BackupYamlTest.php | 176 ++++++ tests/DocumentYamlTest.php | 601 ++++++++++++++++++++ tests/FormatYamlTest.php | 22 + tests/QueryYamlTest.php | 1068 ++++++++++++++++++++++++++++++++++++ 7 files changed, 1928 insertions(+), 2 deletions(-) create mode 100644 src/Format/Yaml.php create mode 100644 tests/BackupYamlTest.php create mode 100644 tests/DocumentYamlTest.php create mode 100644 tests/FormatYamlTest.php create mode 100644 tests/QueryYamlTest.php diff --git a/README.md b/README.md index 32ff311..08cc9ec 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,10 @@ The Default Format Class: `JSON` \Filebase\Format\Json::class ``` +Additional Format Classes: `Yaml` +```php +\Filebase\Format\Yaml::class +``` ## (3) GET (and methods) diff --git a/composer.json b/composer.json index f423c05..231e0e7 100644 --- a/composer.json +++ b/composer.json @@ -18,10 +18,15 @@ }, "require-dev": { - "satooshi/php-coveralls": "^2.0", - "phpunit/phpunit": "5.*" + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "5.*", + "symfony/yaml": "^4.1" }, + "suggest": { + "symfony/yaml": "Allows Yaml format" + }, + "autoload": { "psr-4": { "Filebase\\": "src/" diff --git a/src/Format/Yaml.php b/src/Format/Yaml.php new file mode 100644 index 0000000..e43bc8c --- /dev/null +++ b/src/Format/Yaml.php @@ -0,0 +1,50 @@ + __DIR__.'/databases/mydatabasetobackup', + 'backupLocation' => __DIR__.'/databases/storage/backups', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->backup(); + + $this->assertEquals(true, true); + } + + + public function testBackupLocationDefault() + { + + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/mydatabasetobackup', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->backup(); + + $this->assertEquals(true, true); + } + + + public function testBackupCreate() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/mydatabasetobackup', + 'backupLocation' => __DIR__.'/databases/storage/backups', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 25; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + } + + $file = $db->backup()->create(); + + $db->flush(true); + + $this->assertRegExp('/[0-9]+\.zip$/',$file); + } + + + public function testBackupFind() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/mydatabasetobackup', + 'backupLocation' => __DIR__.'/databases/storage/backups', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 25; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + } + + $db->backup()->create(); + + $backups = $db->backup()->find(); + + $this->assertInternalType('array',$backups); + $this->assertNotEmpty($backups); + } + + + public function testBackupFindSort() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/mydatabasetobackup', + 'backupLocation' => __DIR__.'/databases/storage/backups', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 25; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + } + + $db->backup()->create(); + $db->backup()->create(); + $last = str_replace('.zip','',$db->backup()->create()); + + $backups = $db->backup()->find(); + $backupCurrent = current($backups); + + $lastBackup = str_replace('.zip','',basename($backupCurrent)); + + $db->flush(true); + + $this->assertEquals($last,$lastBackup); + } + + + public function testBackupCleanup() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/mydatabasetobackup', + 'backupLocation' => __DIR__.'/databases/storage/backups', + 'format' => \Filebase\Format\Yaml::class + ]); + + $backupBefore = $db->backup()->find(); + + $db->backup()->clean(); + $backupAfter = $db->backup()->find(); + + $this->assertInternalType('array',$backupBefore); + $this->assertNotEmpty($backupBefore); + + $this->assertInternalType('array',$backupAfter); + $this->assertEmpty($backupAfter); + } + + + public function testBackupRestore() + { + $db1 = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/backupdb', + 'backupLocation' => __DIR__.'/databases/storage/backupdb', + 'format' => \Filebase\Format\Yaml::class + ]); + + for ($x = 1; $x <= 25; $x++) + { + $user = $db1->get(uniqid()); + $user->name = 'John'; + $user->save(); + } + + $db1->backup()->create(); + + $items1 = $db1->count(); + + $db2 = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/backupdb2', + 'backupLocation' => __DIR__.'/databases/storage/backupdb', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db2->backup()->rollback(); + $db2->backup()->clean(); + + $items2 = $db2->count(); + + $db1->flush(true); + $db2->flush(true); + + $this->assertEquals($items1,$items2); + + } + + +} diff --git a/tests/DocumentYamlTest.php b/tests/DocumentYamlTest.php new file mode 100644 index 0000000..713c43d --- /dev/null +++ b/tests/DocumentYamlTest.php @@ -0,0 +1,601 @@ + __DIR__.'/databases', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + // save data + $doc = $db->get('test_save')->save(['key'=>'value']); + + // get saved data (put into array) + $val = $db->get('test_save'); + + // should equal... + $this->assertEquals('value', $val->key); + + #$db->flush(true); + } + + + //-------------------------------------------------------------------- + + + + + /** + * testDoesNotExist() + * + * TEST CASE: + * - Save document with data + * - Get the document + * - Check that the data is there and the document exist + * + */ + public function testDoesNotExist() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + // get saved data (put into array) + $doc = $db->get('doesexist')->save(['key'=>'value']); + + $this->assertEquals(true, $db->has('doesexist')); + + $this->assertEquals(false, $db->has('doesnotexist')); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + + + /** + * testSetIdGetId() + * + * TEST CASE: + * - Set and Get Id + * + */ + public function testSetIdGetId() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/data_rename', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + // save data + $doc = $db->get('name_1')->save(['key'=>'value']); + $this->assertEquals('name_1', $doc->getId()); + + // delete existing doc so its not duplicated + // object still exist, but file has been removed + $doc->delete(); + $this->assertEquals('name_1', $doc->getId()); + + // change id and save (new file is created) + $doc->setId('name_2')->save(); + $this->assertEquals('name_2', $doc->getId()); + } + + + //-------------------------------------------------------------------- + + + /** + * testSetValue() + * + * TEST CASE: + * - Using the set method, set the value in object ( DO NOT SAVE ) + * - Check that the properties are in the object (matching) + * + */ + public function testSetValue() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + // FIRST TEST + // use the set() method + $test1 = $db->get('test1')->set(['key'=>'value']); + + $this->assertEquals('value', $test1->key); + + + // SECOND TEST: + // use the property setter + $test2 = $db->get('test2'); + $test2->key = 'value'; + + $this->assertEquals('value', $test2->key); + + + // THIRD TEST (null test) + $test3 = $db->get('test3'); + + $this->assertEquals(null, $test3->key); + + } + + + //-------------------------------------------------------------------- + + + /** + * testIssetUnsetUnknown() + * + * TEST CASE: + * - Check if property isset + * - Unset property and see if it now returns null + * + */ + public function testIssetUnset() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $test = $db->get('test2'); + $test->key = 'value'; + + $this->assertEquals('value', $test->key); + + $this->assertEquals(1, isset($test->key)); + + unset($test->key); + + $this->assertEquals(null, ($test->key)); + + } + + + //-------------------------------------------------------------------- + + + public function testArraySetValueSave() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $test = $db->get('test'); + + $this->assertEquals('value', $test->key); + + $db->flush(true); + } + + + public function testPropertySetValueSave() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $test = $db->get('test'); + $test->key = 'value'; + $test->save(); + + $test = $db->get('test'); + + $this->assertEquals('value', $test->key); + + $db->flush(true); + } + + + public function testToArray() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $test = $db->get('test')->toArray(); + + $this->assertEquals('value', $test['key']); + + $db->flush(true); + } + + + public function testDelete() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $test = $db->get('test')->delete(); + + $this->assertEquals(true, $test); + + $db->flush(true); + } + + + public function testGetId() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $test = $db->get('test'); + + $this->assertEquals('test', $test->getId()); + + $db->flush(true); + } + + + public function testSetId() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $test = $db->get('test')->setId('newid'); + + $this->assertEquals('newid', $test->getId()); + + $db->flush(true); + } + + + + // DATE TESTS + //-------------------------------------------------------------------- + + public function testDates() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $createdAt = strtotime($db->get('test')->createdAt()); + $updatedAt = strtotime($db->get('test')->updatedAt()); + + $this->assertEquals(date('Y-m-d'), date('Y-m-d',$createdAt)); + $this->assertEquals(date('Y-m-d'), date('Y-m-d',$updatedAt)); + + $db->flush(true); + } + + + public function testFormatDates() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $createdAt = $db->get('test')->createdAt('Y-m-d'); + $updatedAt = $db->get('test')->updatedAt('Y-m-d'); + + $this->assertEquals(date('Y-m-d'), $createdAt); + $this->assertEquals(date('Y-m-d'), $updatedAt); + + $db->flush(true); + } + + + public function testNoFormatDates() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $createdAt = $db->get('test')->createdAt(false); + $updatedAt = $db->get('test')->updatedAt(false); + + $this->assertEquals(date('Y-m-d'), date('Y-m-d',$createdAt)); + $this->assertEquals(date('Y-m-d'), date('Y-m-d',$updatedAt)); + + $db->flush(true); + } + + + public function testMissingUpdatedDate() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('test')->set(['key'=>'value'])->save(); + + $setUpdatedAt = $db->get('test')->setUpdatedAt(null); + $setCreatedAt = $db->get('test')->setCreatedAt(null); + + $this->assertEquals(date('Y-m-d'), $setCreatedAt->updatedAt('Y-m-d')); + $this->assertEquals(date('Y-m-d'), $setUpdatedAt->updatedAt('Y-m-d')); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + public function testCustomFilter() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $u = []; + $u[] = [ + 'email' => 'email@email.com', + 'status' => 'blocked' + ]; + + $u[] = [ + 'email' => 'notblocked@email.com', + 'status' => 'enabled' + ]; + + $db->get('users')->set($u)->save(); + + $users = $db->get('users')->customFilter('data',function($item) { + return (($item['status']=='blocked') ? $item['email'] : false); + }); + + $this->assertEquals(1, count($users)); + $this->assertEquals('email@email.com', $users[0]); + + $db->flush(true); + } + + + public function testCustomFilterParam() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $u = []; + $u[] = [ + 'email' => 'email@email.com', + 'status' => 'blocked' + ]; + + $u[] = [ + 'email' => 'notblocked@email.com', + 'status' => 'enabled' + ]; + + $db->get('users')->set($u)->save(); + + $users = $db->get('users')->customFilter('data','enabled',function($item, $status) { + return (($item['status']==$status) ? $item['email'] : false); + }); + + $this->assertEquals(1, count($users)); + $this->assertEquals('notblocked@email.com', $users[0]); + + $db->flush(true); + } + + + + public function testCustomFilterParamIndex() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $u = []; + $u[] = [ + 'email' => 'enabled-email@email.com', + 'id' => '123', + 'status' => 'deactive' + ]; + + $u[] = [ + 'email' => 'enabled-email@email.com', + 'id' => '321', + 'status' => 'enabled' + ]; + + $db->get('users_test_custom')->save($u); + + $users = $db->get('users_test_custom')->filter('data','enabled',function($item, $status) { + return (($item['status']==$status) ? $item : false); + }); + + + $this->assertEquals(1, count($users)); + $this->assertEquals('enabled-email@email.com', $users[0]['email']); + + $db->flush(true); + } + + + public function testCustomFilterEmpty() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('customfilter_test')->set(['email'=>'time'])->save(); + + $users = $db->get('customfilter_test')->customFilter('email',function($item) { + return (($item['status']=='blocked') ? $item['email'] : false); + }); + + // should be empty array + $this->assertEquals([],$users); + + $db->flush(true); + } + + + public function testFieldMethod() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('user_test_email_1')->set(['email'=>'example@example.com'])->save(); + + $f = $db->get('user_test_email_1')->field('email'); + + $this->assertEquals('example@example.com', $f); + + $db->flush(true); + } + + + public function testNestedFieldMethod() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $db->get('user_test_email_2')->set([ + 'profile' => [ + 'email' => 'example@example.com' + ] + ])->save(); + + $f = $db->get('user_test_email_2')->field('profile.email'); + + $this->assertEquals('example@example.com', $f); + + $db->flush(true); + } + + + public function testBadNameException() + { + $this->expectException(\Exception::class); + + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'safe_filename' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $file = $db->get('^*bad_@name%$1#'); + + $db->flush(true); + } + + + public function testBadNameReplacement() + { + $badName = 'ti^@%mo!!~th*y-m_?a(ro%)is.&'; + $newName = Filesystem::validateName($badName, true); + + $this->assertEquals('timothy-m_arois', $newName); + } + + + public function testBadNameReplacementLong() + { + $badName = '1234567890123456789012345678901234567890123456789012345678901234'; + $newName = Filesystem::validateName($badName, true); + + $this->assertEquals(63, (strlen($newName)) ); + $this->assertEquals('123456789012345678901234567890123456789012345678901234567890123', $newName); + } + +} diff --git a/tests/FormatYamlTest.php b/tests/FormatYamlTest.php new file mode 100644 index 0000000..b571c53 --- /dev/null +++ b/tests/FormatYamlTest.php @@ -0,0 +1,22 @@ + 'timothy-m_arois', + 'email' => 'email@email.com' + ]; + + $Yaml = Yaml::encode($data, false); + $testData = Yaml::decode($Yaml); + + $this->assertEquals($data, $testData); + } + +} \ No newline at end of file diff --git a/tests/QueryYamlTest.php b/tests/QueryYamlTest.php new file mode 100644 index 0000000..29efa27 --- /dev/null +++ b/tests/QueryYamlTest.php @@ -0,0 +1,1068 @@ + ["name" => "Roy"] ]) + * + * Comparisons used "=", "==", "===" + * + */ + public function testWhereCountAllEqualCompare() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + // FIRST TEST + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->contact['email'] = 'john@john.com'; + $user->save(); + } + + $count = $db->count(); + + // standard matches + $query1 = $db->query()->where('name','=','John')->results(); + $query2 = $db->query()->where('name','==','John')->results(); + $query3 = $db->query()->where('name','===','John')->results(); + $query4 = $db->query()->where(['name' => 'John'])->results(); + + // testing nested level + $query5 = $db->query()->where('contact.email','=','john@john.com')->results(); + + $this->assertEquals($count, count($query1)); + $this->assertEquals($count, count($query2)); + $this->assertEquals($count, count($query3)); + $this->assertEquals($count, count($query4)); + $this->assertEquals($count, count($query5)); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testWhereCountAllNotEqualCompare() + * + * TEST CASE: + * - Creates 10 items in database with ["name" = "John"] + * - Counts the total items in the database + * + * FIRST TEST: + * - Compares the number of items in db to the number items the query found + * - Should match "10" + * + * SECOND TEST: + * - Secondary Tests to find items that DO NOT match "John" + * - Should match "0" + * + * Comparisons used "!=", "!==", "NOT" + * + */ + public function testWhereCountAllNotEqualCompare() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + } + + $count = $db->count(); + + $query1 = $db->query()->where('name','!=','Max')->results(); + $query2 = $db->query()->where('name','!==','Smith')->results(); + $query3 = $db->query()->where('name','NOT','Jason')->results(); + + $query4 = $db->query()->where('name','!=','John')->results(); + $query5 = $db->query()->where('name','!==','John')->results(); + $query6 = $db->query()->where('name','NOT','John')->results(); + + $this->assertEquals($count, count($query1)); + $this->assertEquals($count, count($query2)); + $this->assertEquals($count, count($query3)); + + $this->assertEquals(0, count($query4)); + $this->assertEquals(0, count($query5)); + $this->assertEquals(0, count($query6)); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + + /** + * testWhereCountAllGreaterLessCompare() + * + * TEST CASE: + * - Creates 10 items in database with ["pages" = 5] + * - Counts the total items in the database + * + * FIRST TEST: Greater Than + * - Should match "10" + * + * SECOND TEST: Less Than + * - Should match "10" + * + * THIRD TEST: Less/Greater than "no match" + * - Should match "0" + * + * Comparisons used ">=", ">", "<=", "<" + * + */ + public function testWhereCountAllGreaterLessCompare() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->index = $x; + $user->index2 = mt_rand(1,2); + $user->pages = 5; + $user->save(); + } + + $count = $db->count(); + + $queryIndex = $db->query() + ->where('pages','>','4') + ->where('index','=','1') + ->where('index2','=','2') + ->results(); + + // print_r($queryIndex); + + // FIRST TEST + $query1 = $db->query()->where('pages','>','4')->results(); + $query2 = $db->query()->where('pages','>=','5')->results(); + + // SECOND TEST + $query3 = $db->query()->where('pages','<','6')->results(); + $query4 = $db->query()->where('pages','<=','5')->results(); + + // THIRD TEST + $query5 = $db->query()->where('pages','>','5')->results(); + $query6 = $db->query()->where('pages','<','5')->results(); + + $this->assertEquals($count, count($query1)); + $this->assertEquals($count, count($query2)); + $this->assertEquals($count, count($query3)); + $this->assertEquals($count, count($query4)); + $this->assertEquals(0, count($query5)); + $this->assertEquals(0, count($query6)); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testWhereLike() + * + * TEST CASE: + * - Creates a bunch of items with the same information + * - Creates one item with different info (finding the needle) + * + * Comparisons used "LIKE", "NOT LIKE", "==" + * + */ + public function testWhereLike() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_like', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John Ellot'; + $user->email = 'johnellot@example.com'; + $user->save(); + } + + // the needle + $user = $db->get(uniqid()); + $user->name = 'Timothy Marois'; + $user->email = 'timothymarois@email.com'; + $user->save(); + + $count = $db->count(); + + // should return exact match + $query1 = $db->query()->where('name','==','Timothy Marois')->results(); + // this should fail to find anything + $query2 = $db->query()->where('name','==','timothy marois')->results(); + + // this should find match with regex loose expression + $query3 = $db->query()->where('name','LIKE','timothy marois')->results(); + // this should find match by looking for loose expression on "timothy" + $query4 = $db->query()->where('name','LIKE','timothy')->results(); + // this should find all teh users that have an email address using "@email.com" + $query5 = $db->query()->where('email','LIKE','@email.com')->results(); + // this should return 1 as its looking at only the emails not like "@example.com" + $query6 = $db->query()->where('email','NOT LIKE','@example.com')->results(); + + $this->assertEquals(1, count($query1)); + $this->assertEquals(0, count($query2)); + $this->assertEquals(1, count($query3)); + $this->assertEquals(1, count($query4)); + $this->assertEquals(1, count($query5)); + $this->assertEquals(1, count($query6)); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testWhereRegex() + * + * TEST CASE: + * - Testing the use of regex + * + * Comparisons used "REGEX" + * + */ + public function testWhereRegex() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_regex', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John Ellot'; + $user->email = 'johnellot@example.com'; + $user->save(); + } + + // the needle (with bad email) + $user = $db->get(uniqid()); + $user->name = 'Leo Ash'; + $user->email = 'example@emailcom'; + $user->save(); + + $count = $db->count(); + + // this should find match with regex loose expression + $query1 = $db->query()->where('name','REGEX','/leo/i')->results(); + $query2 = $db->query()->where('name','REGEX','/leo\sash/i')->results(); + + // finds all the emails in a field + $query3 = $db->query()->where('email','REGEX','/[a-z\d._%+-]+@[a-z\d.-]+\.[a-z]{2,4}\b/i')->results(); + + $this->assertEquals(1, count($query1)); + $this->assertEquals(1, count($query2)); + $this->assertEquals(10, count($query3)); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testLimitOffset() + * + * TEST CASE: + * - Creates 6 company profiles + * - Queries them and limits the results + * + * + */ + public function testLimitOffset() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_orderby', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $companies = ['Google'=>150, 'Apple'=>150, 'Microsoft'=>150, 'Amex'=>150, 'Hooli'=>20, 'Amazon'=>10]; + + foreach($companies as $company=>$rank) + { + $user = $db->get(uniqid()); + $user->name = $company; + $user->rank = $rank; + $user->save(); + } + + // test that it limits the results to "2" (total query pulls "5") + $test1 = $db->query()->where('rank','=',150)->limit(2)->results(); + + // test the offset, no limit, should be 3 (total query pulls "5") + $test2 = $db->query()->where('rank','=',150)->limit(0,1)->results(); + + // test that the offset takes off the first array (should return "apple", not "google") + $test3 = $db->query()->where('rank','=',150)->limit(1,1)->results(); + + $this->assertEquals(2, (count($test1))); + $this->assertEquals(3, (count($test2))); + $this->assertEquals('Apple', $test3[0]['name']); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + /** + * testSorting() + * + * TEST CASE: + * - Creates 6 company profiles + * - Sorts them by DESC/ASC + * + * + */ + /*public function testSelectQuery() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_select', + 'cache' => false, 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $users = [ + 'JR MM'=> + [ + 'about'=>'this is a long about me section', + 'email'=>'jrmm@email.com', + 'profile' => [ + 'website' => 'jr.com' + ] + ], + 'Tim'=> + [ + 'about'=>'this is a section about tim', + 'email'=>'timothymarois@email.com', + 'profile' => [ + 'website' => 'timothymarois.com' + ] + ] + ]; + foreach($users as $name=>$info) + { + $user = $db->get(uniqid()); + $user->name = $name; + $user->about = $info['about']; + $user->email = $info['email']; + $user->profile = $info['profile']; + $user->save(); + } + + // return the "name" (selecting only 1 item) + $test1 = $db->query()->select('name')->results(); + $this->assertEquals(['JR MM','Tim'], [$test1[0]['name'],$test1[1]['name']]); + // count how many items are in array (should be only 1 each) + $this->assertEquals([1,1], [count($test1[0]),count($test1[1])]); + + // return the "name" (selecting only 1 item) + $test2 = $db->query()->select('name,email')->first(); + $this->assertEquals(['JR MM','jrmm@email.com'], [$test2['name'],$test2['email']]); + + // select using arrays instead of strings + $test3 = $db->query()->select(['name','email'])->first(); + $this->assertEquals(['JR MM','jrmm@email.com'], [$test3['name'],$test3['email']]); + + // return the "name" (selecting only 1 item) + // currently DOES not work with nested.. + // $test3 = $db->query()->select('name,profile.website')->first(); + + // print_r($test3); + // $this->assertEquals(['JR MM','jrmm@email.com'], [$test2['name'],$test2['email']]); + }*/ + + + /** + * testSorting() + * + * TEST CASE: + * - Creates 6 company profiles + * - Sorts them by DESC/ASC + * + * + */ + public function testSorting() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_orderby', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $companies = ['Google'=>150, 'Apple'=>180, 'Microsoft'=>120, 'Amex'=>20, 'Hooli'=>50, 'Amazon'=>140]; + + foreach($companies as $company=>$rank) + { + $user = $db->get(uniqid()); + $user->name = $company; + $user->rank['reviews'] = $rank; + $user->status = 'enabled'; + $user->save(); + } + + // test that they are ordered by name ASC (check first, second, and last) + $test1 = $db->query()->where('status','=','enabled')->orderBy('name', 'ASC')->results(); + $this->assertEquals(['first'=>'Amazon','second'=>'Amex','last'=>'Microsoft'], ['first'=>$test1[0]['name'],'second'=>$test1[1]['name'],'last'=>$test1[5]['name']]); + + // test that they are ordered by name ASC (check first, second, and last) + $test2 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('name', 'ASC')->results(); + $this->assertEquals(['Amazon','Amex','Apple'], [$test2[0]['name'],$test2[1]['name'],$test2[2]['name']]); + + // test that they are ordered by name DESC (check first, second, and last) + $test3 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('name', 'DESC')->results(); + $this->assertEquals(['Microsoft','Hooli','Google'], [$test3[0]['name'],$test3[1]['name'],$test3[2]['name']]); + + // test that they are ordered by rank nested [reviews] DESC + $test4 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('rank.reviews', 'DESC')->results(); + $this->assertEquals(['Apple','Google','Amazon'], [$test4[0]['name'],$test4[1]['name'],$test4[2]['name']]); + + // test that they are ordered by rank nested [reviews] ASC + $test5 = $db->query()->where('status','=','enabled')->limit(3)->orderBy('rank.reviews', 'ASC')->results(); + $this->assertEquals(['Amex','Hooli','Microsoft'], [$test5[0]['name'],$test5[1]['name'],$test5[2]['name']]); + + $db->flush(true); + + $companies = ['Google 9', 'Google 3', 'Google 10', 'Google 1', 'Google 2', 'Google 7']; + + foreach($companies as $company) + { + $user = $db->get(uniqid()); + $user->name = $company; + $user->save(); + } + + // order the results ASC (but inject numbers into strings) + $test6 = $db->query()->limit(3)->orderBy('name', 'ASC')->results(); + $this->assertEquals(['Google 1','Google 2','Google 3'], [$test6[0]['name'],$test6[1]['name'],$test6[2]['name']]); + + // order the results DESC (but inject numbers into strings) + $test6 = $db->query()->limit(3)->orderBy('name', 'DESC')->results(); + $this->assertEquals(['Google 10','Google 9','Google 7'], [$test6[0]['name'],$test6[1]['name'],$test6[2]['name']]); + + $db->flush(true); + + } + + + //-------------------------------------------------------------------- + + + /** + * testWhereIn() + * + * TEST CASE: + * - Testing the Where "IN" operator + * + * + */ + public function testWhereIn() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $companies = [ + 'Google'=>[ + 'tags' => [ + 'search','display' + ] + ], + 'Facebook'=>[ + 'tags' => [ + 'social','network' + ] + ], + 'Microsoft'=>[ + 'tags' => [ + 'windows','xbox','search' + ] + ] + ]; + + foreach($companies as $company=>$tags) + { + $user = $db->get(uniqid()); + $user->name = $company; + $user->tags = $tags['tags']; + $user->save(); + } + + + // test that they are ordered by name ASC (check first, second, and last) + $test1 = $db->query()->where('tags','IN','display')->first(); + $test2 = $db->query()->where('tags','IN','network')->first(); + $test3 = $db->query()->where('tags','IN','windows')->first(); + $test4 = $db->query()->where('tags','IN','search')->results(); + + // testing the object return boolean argument + $test5 = $db->query()->where('tags','IN','search')->results(false); + $test6 = $db->query()->where('tags','IN','search')->results(true); + + // make sure the results equal the right names + $this->assertEquals('Google', $test1['name']); + $this->assertEquals('Facebook', $test2['name']); + $this->assertEquals('Microsoft', $test3['name']); + + // check if the method createdAt() exists or not based on the argument boolean + $this->assertEquals(true, method_exists($test5[0], 'createdAt')); + $this->assertEquals(false, method_exists($test6[0], 'createdAt')); + + // check if the results = 2 + $this->assertEquals(2, count($test4)); + + // this will test the IN clause if name matches one of these + $test3 = $db->query()->where('name','IN',['Google','Facebook'])->results(); + + $this->assertEquals(2, count($test3)); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testWithoutWhere() + * + * TEST CASE: + * - Run queries without using Where() + * - This will run a findAll() + * + * + */ + public function testWithoutWhere() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $companies = [ + 'Google'=>[ + 'site' => 'google.com', + 'type' => 'search' + ], + 'Yahoo'=>[ + 'site' => 'yahoo.com', + 'type' => 'search' + ], + 'Facebook'=>[ + 'site' => 'facebook.com', + 'type' => 'social' + ] + ]; + + foreach($companies as $company=>$options) + { + $user = $db->get(uniqid()); + $user->name = $company; + $user->type = $options['type']; + $user->site = $options['site']; + $user->save(); + } + + + // test that they are ordered by name ASC (check first, second, and last) + $test1 = $db->query()->orderBy('name', 'DESC')->first(); + $test2 = $db->query()->orderBy('name', 'DESC')->first( false ); + $test3 = $db->query()->orderBy('name', 'DESC')->first( true ); + + $this->assertEquals(true, method_exists($test2, 'createdAt')); + $this->assertEquals(false, method_exists($test3, 'createdAt')); + + $this->assertEquals('Yahoo', $test1['name']); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testingBadOperator() + * + * BAD TEST CASE: + * - Tries to run a query with an operator that does not exist. + * + */ + public function testingBadOperator() + { + $this->expectException(\InvalidArgumentException::class); + + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + // FIRST TEST + $db->flush(true); + + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + + // standard matches + $query = $db->query()->where('name','&','John')->results(); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testingBadField() + * + * BAD TEST CASE: + * - Tries to run a query with a blank field + * + */ + public function testingBadField() + { + $this->expectException(\InvalidArgumentException::class); + + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + // FIRST TEST + $db->flush(true); + + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + + // standard matches + $query = $db->query()->where('','=','John')->results(); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testingMissingQueryArguments() + * + * BAD TEST CASE: + * - Tries to run a query with just a string arg + * + */ + public function testingMissingQueryArguments() + { + $this->expectException(\InvalidArgumentException::class); + + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->save(); + + // standard matches + $query = $db->query()->where('John')->results(); + + $db->flush(true); + } + + + + //-------------------------------------------------------------------- + + + /** + * testUserNameQuery() + * + * + */ + public function testUserNameQuery() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_names', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John '.$x; + $user->contact['email'] = 'john@john.com'; + $user->save(); + } + + $userAccountFirst = $db->query()->orderBy('name', 'DESC')->first(); + $userAccountLast = $db->query()->orderBy('name', 'DESC')->last(); + + // testing "first" method and sorting + $this->assertEquals('John 10', $userAccountFirst['name']); + + // testing "last" method and sorting + $this->assertEquals('John 1', $userAccountLast['name']); + + $db->flush(true); + } + + + //-------------------------------------------------------------------- + + + /** + * testQueryCount() + * + * + */ + public function testQueryCount() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_qcounter', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John '.$x; + $user->contact['email'] = 'john@john.com'; + $user->save(); + } + + $userCount1 = $db->query()->count(); + $userCount2 = $db->query()->where('name','==','Nothing')->count(); + $userCount3 = $db->query()->where('name','==','John 2')->count(); + + // find users that have the number 1 in their name (should be 2) + // John 1 and John 10 + $userCount4 = $db->query()->where('name','REGEX','/1/')->count(); + + // should = 10 documents + $this->assertEquals(10, $userCount1); + $this->assertEquals(0, $userCount2); + $this->assertEquals(1, $userCount3); + $this->assertEquals(2, $userCount4); + + $db->flush(true); + } + + + + //-------------------------------------------------------------------- + + + + + + public function testWhereQueryWhereCount() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->criteria = [ + 'label' => 'lead' + ]; + + $user->save(); + } + + $results = $db->query() + ->where('name','=','John') + ->andWhere('email','==','john@example.com') + ->results(); + + $this->assertEquals($db->count(), count($results)); + + $db->flush(true); + $db->flushCache(); + } + + + public function testWhereQueryFindNameCount() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_2', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + + if ($x < 6) + { + $user->name = 'John'; + } + else + { + $user->name = 'Max'; + } + + $user->save(); + } + + $results = $db->query() + ->where('name','=','John') + ->results(); + + $this->assertEquals(5, count($results)); + + #$db->flush(true); + $db->flushCache(); + } + + + + public function testOrWhereQueryCount() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + + if ($x < 6) + { + $user->name = 'John'; + } + else + { + $user->name = 'Max'; + } + + $user->save(); + } + + $results = $db->query() + ->where('name','=','John') + ->orWhere('name','=','Max') + ->results(); + + $this->assertEquals($db->count(), count($results)); + + $db->flush(true); + $db->flushCache(); + } + + + public function testWhereQueryFromCache() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->save(); + } + + $results = $db->query() + ->where('name','=','John') + ->andWhere('email','==','john@example.com') + ->resultDocuments(); + + $result_from_cache = $db->query() + ->where('name','=','John') + ->andWhere('email','==','john@example.com') + ->resultDocuments(); + + $this->assertEquals(10, count($results)); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); + + $db->flush(true); + } + + + public function testQueryFromCacheAfterDelete() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/deleted', + 'cache' => true, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->save(); + } + + $results = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + $result_from_cache = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + + $this->assertEquals(10, count($results)); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); + + $id = $result_from_cache[0]->getId(); + $id2 = $result_from_cache[1]->getId(); + + // delete the file + $result_from_cache[0]->delete(); + + $results = $db->query() + ->where('name','=','John') + ->andWhere('email','==','john@example.com') + ->resultDocuments(); + + $this->assertEquals($id2, $results[0]->getId()); + + $db->flush(true); + } + + + + public function testQueryFromCacheAfterSave() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/saved', + 'cache' => true, + 'format' => \Filebase\Format\Yaml::class + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->save(); + } + + $results = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + $result_from_cache = $db->query()->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + + $this->assertEquals(10, count($results)); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); + + $id = $result_from_cache[0]->getId(); + $id2 = $result_from_cache[1]->getId(); + + // Change the name + $result_from_cache[0]->name = 'Tim'; + $result_from_cache[0]->save(); + + $results = $db->query() + ->where('name','=','John') + ->andWhere('email','==','john@example.com') + ->resultDocuments(); + + $this->assertEquals($id2, $results[0]->getId()); + $this->assertEquals('John', $results[0]->name); + + $db->flush(true); + } + +} From e1792e7b1d5e125f18d592b6ce79e3098f533b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Sat, 29 Sep 2018 15:21:11 +0200 Subject: [PATCH 13/51] Only unlink existing files --- src/Filesystem.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Filesystem.php b/src/Filesystem.php index 2e37950..de16f24 100644 --- a/src/Filesystem.php +++ b/src/Filesystem.php @@ -66,6 +66,10 @@ public static function write($path, $contents) */ public static function delete($path) { + if (!file_exists($path)) { + return true; + } + return unlink($path); } From 1a06682eeb0f9b6c62b39ab96561bfd49dbf0db5 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Wed, 26 Dec 2018 19:00:22 -0500 Subject: [PATCH 14/51] Updated readme for composer install --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32ff311..4cc0a34 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Filebase is simple by design, but has enough features for the more advanced. Use [Composer](http://getcomposer.org/) to install package. -Run `composer require filebase/filebase` +Run `composer require filebase/filebase:^1.0` If you do not want to use composer, download the files, and include it within your application, it does not have any dependencies, you will just need to keep it updated with any future releases. From 433190a2474a715ad3e23c8d3d74e39990cc9f77 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Wed, 26 Dec 2018 19:27:21 -0500 Subject: [PATCH 15/51] Updated composer symfony/yaml to allow php 5.6 --- .travis.yml | 1 + CHANGELOG.md | 3 +++ composer.json | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9114ce2..102886d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 5.6 - 7 - 7.1 + - 7.2 sudo: required dist: precise diff --git a/CHANGELOG.md b/CHANGELOG.md index a71e0a9..7a8ac76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Change Log ========== +### 12/26/2018 - 1.0.21 +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/30) for YAML format. + ### 08/16/2018 - 1.0.20 * Fixed #23 – Caching is cleared when deleting/saving documents to prevent cache from being out of sync with document data. diff --git a/composer.json b/composer.json index 231e0e7..13a3e3b 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.0", "phpunit/phpunit": "5.*", - "symfony/yaml": "^4.1" + "symfony/yaml": "^3.4" }, "suggest": { From fbe4e8dd3a1feaf5c48df308e983463ae365461f Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Thu, 7 Feb 2019 21:15:46 -0600 Subject: [PATCH 16/51] #42 Sort by update or create time --- src/Document.php | 10 +++++++++ tests/DocumentTest.php | 20 +++++++++++++++++ tests/QueryTest.php | 50 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/src/Document.php b/src/Document.php index 09daa06..e064619 100644 --- a/src/Document.php +++ b/src/Document.php @@ -434,6 +434,16 @@ public function field($field) return $context; } + if ($field == '__created_at') + { + return $this->__created_at; + } + + if ($field == '__updated_at') + { + return $this->__updated_at; + } + foreach($parts as $part) { if (trim($part) == '') diff --git a/tests/DocumentTest.php b/tests/DocumentTest.php index 45dc7f3..133db3f 100644 --- a/tests/DocumentTest.php +++ b/tests/DocumentTest.php @@ -518,6 +518,26 @@ public function testFieldMethod() $db->flush(true); } + public function testFieldTimestamps() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases' + ]); + + $db->flush(true); + + $db->get('vegetables')->set(['broccoli'=>'27'])->save(); + + $expected = time(); + $actual = $db->get('vegetables')->field('__created_at'); + $this->assertEquals($expected, $actual); + + $actual = $db->get('vegetables')->field('__updated_at'); + $this->assertEquals($expected, $actual); + + $db->flush(true); + } + public function testNestedFieldMethod() { diff --git a/tests/QueryTest.php b/tests/QueryTest.php index c5a1db4..0c027e8 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1045,4 +1045,54 @@ public function testQueryFromCacheAfterSave() $db->flush(true); } + public function testSortByTimes() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/_testsort' + ]); + + $db->flush(true); + + // Create some docs with time in between to get different timestamps + $doc = $db->get('record1')->set(['name'=>'a'])->save(); + sleep(1); + $doc = $db->get('record2')->set(['name'=>'b'])->save(); + sleep(1); + $doc = $db->get('record3')->set(['name'=>'c'])->save(); + + $documents = $db->query()->orderBy('__created_at', 'DESC')->results(); + $expected = [ + ['name' => 'c'], + ['name' => 'b'], + ['name' => 'a'], + ]; + $this->assertEquals($expected, $documents); + + $documents = $db->query()->orderBy('__created_at', 'ASC')->results(); + $expected = [ + ['name' => 'a'], + ['name' => 'b'], + ['name' => 'c'], + ]; + $this->assertEquals($expected, $documents); + + $documents = $db->query()->orderBy('__updated_at', 'DESC')->results(); + $expected = [ + ['name' => 'c'], + ['name' => 'b'], + ['name' => 'a'], + ]; + $this->assertEquals($expected, $documents); + + $documents = $db->query()->orderBy('__updated_at', 'ASC')->results(); + $expected = [ + ['name' => 'a'], + ['name' => 'b'], + ['name' => 'c'], + ]; + $this->assertEquals($expected, $documents); + + $db->flush(true); + } + } From f4badc8437ff47782c34c8b6abbf84d5f48b0794 Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Fri, 8 Feb 2019 16:57:33 -0600 Subject: [PATCH 17/51] #40 Add ability to query on document ids --- src/Document.php | 4 ++++ tests/DocumentTest.php | 16 ++++++++++++++++ tests/QueryTest.php | 31 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/Document.php b/src/Document.php index 09daa06..50c2b58 100644 --- a/src/Document.php +++ b/src/Document.php @@ -434,6 +434,10 @@ public function field($field) return $context; } + if ($field == '__id') { + return $this->__id; + } + foreach($parts as $part) { if (trim($part) == '') diff --git a/tests/DocumentTest.php b/tests/DocumentTest.php index 45dc7f3..7e747ce 100644 --- a/tests/DocumentTest.php +++ b/tests/DocumentTest.php @@ -518,6 +518,22 @@ public function testFieldMethod() $db->flush(true); } + public function testFieldId() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases' + ]); + + $db->flush(true); + + $db->get('weather')->set(['cityname'=>'condition1'])->save(); + + $actual = $db->get('weather')->field('__id'); + $this->assertEquals('weather', $actual); + + $db->flush(true); + } + public function testNestedFieldMethod() { diff --git a/tests/QueryTest.php b/tests/QueryTest.php index c5a1db4..25e6d0b 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1045,4 +1045,35 @@ public function testQueryFromCacheAfterSave() $db->flush(true); } + /** + * testWhereInUsingDocId + * + * TEST CASE: + * - Testing the where "IN" operator when applied to the document ids to fetch + */ + public function testWhereInUsingDocId() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/users_1', + 'cache' => false + ]); + + $db->flush(true); + + $user1 = $db->get('obj1')->save(['name' => 'Bob']); + $user2 = $db->get('obj2')->save(['name' => 'Jenny']); + $user3 = $db->get('obj3')->save(['name' => 'Cyrus']); + + // Make sure it works with just one + $test1 = $db->query()->where('__id', '=', 'obj1')->first(); + $expected = ['name' => 'Bob']; + $this->assertEquals($expected, $test1); + + // Make sure it works with a list + $test2 = $db->query()->where('__id', 'IN', ['obj2', 'obj3'])->results(); + $expected = [['name' => 'Jenny'], ['name' => 'Cyrus']]; + $this->assertEquals($expected, $test2); + + $db->flush(true); + } } From a1b57bcd31218001e74ec33f72f46d61a4e8d15c Mon Sep 17 00:00:00 2001 From: faryar Date: Sun, 10 Feb 2019 00:36:21 +0330 Subject: [PATCH 18/51] add delete method for remove items with custom filter --- src/Query.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Query.php b/src/Query.php index 62869ac..985da4e 100644 --- a/src/Query.php +++ b/src/Query.php @@ -269,5 +269,21 @@ public function toArray() //-------------------------------------------------------------------- - + + public function delete($input) + { + $items=$this->resultDocuments(); + $condition=$input; + foreach($items as $item) + { + if(is_object($input)) + { + $condition=$input($item); + } + if($condition) + { + $item->delete(); + } + } + } } From 5cd3f44558337b197d712e4618769215a3da22a3 Mon Sep 17 00:00:00 2001 From: faryar Date: Sun, 10 Feb 2019 00:37:06 +0330 Subject: [PATCH 19/51] add unit test for delete (delete with closure) --- tests/QueryTest.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/QueryTest.php b/tests/QueryTest.php index c5a1db4..d1a9911 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1044,5 +1044,39 @@ public function testQueryFromCacheAfterSave() $db->flush(true); } + public function testDeleteWhereMatchItemsWithCustomFilter() + { + $db = new \Filebase\Database([ + 'dir' => 'path/to/users/users/test', + ]); + $db->flush(true); + + $a=0; + while($a < 15) + { + $user=$db->get($a."username"); + $user->name = $a.'John'; + $user->email = 'john@example.com'; + $user->tags = ['php','developer','html5']; + + $user->save(); + $a++; + } + $actual=$db->query()->results(); + $this->assertCount(15,$actual); + $r=$db->query()->where('name','LIKE','john')->resultDocuments(); + $this->assertInstanceOf(Document::class, $r[0]); + + $db->query()->where('name','LIKE','john')->delete(function($item){ + + return $item->name=='0John'; + + }); + $actual=$db->query()->where('name','LIKE','john')->resultDocuments(); + $this->assertCount(14,$actual); + $db->flush(true); + + } + } From 686939d5fafacdafb620f05393a7cb4cfd3a20fa Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Thu, 14 Feb 2019 10:31:57 -0600 Subject: [PATCH 20/51] Add ability to sort by multiple fields --- src/Query.php | 13 +++++++++---- src/QueryLogic.php | 20 ++++++++++++++------ tests/QueryTest.php | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/Query.php b/src/Query.php index 62869ac..f748e88 100644 --- a/src/Query.php +++ b/src/Query.php @@ -7,8 +7,8 @@ class Query extends QueryLogic protected $fields = []; protected $limit = 0; protected $offset = 0; - protected $sortBy = 'ASC'; - protected $orderBy = ''; + protected $sortBy = ['ASC']; + protected $orderBy = ['']; /** @@ -116,8 +116,13 @@ public function limit($limit, $offset = 0) */ public function orderBy($field, $sort) { - $this->orderBy = $field; - $this->sortBy = $sort; + if (count($this->orderBy) == 1 && $this->orderBy[0] == '') { + $this->orderBy[0] = $field; + $this->sortBy[0] = $sort; + } else { + $this->orderBy[] = $field; + $this->sortBy[] = $sort; + } return $this; } diff --git a/src/QueryLogic.php b/src/QueryLogic.php index 764e190..2f275b4 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -190,24 +190,30 @@ protected function offsetLimit() * sort * */ - protected function sort() + protected function sort($orderBy = null, $sortBy = null, $i = 0) { - $orderBy = $this->orderBy; - $sortBy = $this->sortBy; + $orderBy = ($orderBy == null) ? $this->orderBy[$i] : $orderBy; + $sortBy = ($sortBy == null) ? $this->sortBy[$i] : $sortBy; if ($orderBy=='') { return false; } - usort($this->documents, function($a, $b) use ($orderBy, $sortBy) { + $user_sort_function = function($a, $b) use ($orderBy, $sortBy, $i) { $propA = $a->field($orderBy); $propB = $b->field($orderBy); if (strnatcasecmp($propB, $propA) == strnatcasecmp($propA, $propB)) { - return 0; + if (!isset($this->orderBy[$i + 1])) { + return 0; + } + // If they match and there are multiple orderBys, go deeper (recurse) + printf("going deeper %s %s\n", $i, $this->orderBy[$i + 1]); + $i = $i + 1; + return $user_sort_function($this->orderBy[$i], $this->sortBy[$i]); } if ($sortBy == 'DESC') @@ -219,7 +225,9 @@ protected function sort() return (strnatcasecmp($propA, $propB) < strnatcasecmp($propB, $propA)) ? -1 : 1; } - }); + }; + + usort($this->documents, $user_sort_function); } diff --git a/tests/QueryTest.php b/tests/QueryTest.php index c5a1db4..66fc4dc 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -498,6 +498,38 @@ public function testSorting() } + public function testMultiOrderby() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__ . '/databases/users_orderbymult', + 'cache' => false + ]); + + $db->flush(true); + + $companies = ['Google'=>['CA', 150], 'Apple'=>['CA', 180], 'Microsoft'=>['WA', 120], 'Amex'=>['DC', 20], 'Hooli'=>['CA', 50], 'Amazon'=>['PA', 140]]; + + foreach ($companies as $company => $data) { + $doc = $db->get(uniqid()); + $doc->name = $company; + $doc->location = $data[0]; + $doc->rank['reviews'] = $data[1]; + $doc->status = 'enabled'; + $doc->save(); + } + + $test0 = $db->query()->orderBy('location', 'ASC')->results(); + + $test1 = $db->query()->orderBy('location', 'ASC')->orderBy('name', 'ASC')->results(); + $actual = array_map(function($doc) { + return $doc['name']; + }, $test1); + $expected = ['Apple', 'Google', 'Hooli', 'Amex', 'Amazon', 'Microsoft']; + $this->assertEquals($expected, $actual); + + $db->flush(true); + } + //-------------------------------------------------------------------- From 57898279f23f89265abfef48544adb3d489188cd Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Thu, 14 Feb 2019 22:16:24 -0600 Subject: [PATCH 21/51] Correct logic in multi-sortorder queries --- src/Query.php | 7 ++-- src/QueryLogic.php | 39 +++------------------- src/SortLogic.php | 79 +++++++++++++++++++++++++++++++++++++++++++++ tests/QueryTest.php | 66 +++++++++++++++++++++++++++++++++++-- 4 files changed, 151 insertions(+), 40 deletions(-) create mode 100644 src/SortLogic.php diff --git a/src/Query.php b/src/Query.php index f748e88..7334dbe 100644 --- a/src/Query.php +++ b/src/Query.php @@ -114,14 +114,15 @@ public function limit($limit, $offset = 0) * ->orderBy() * */ - public function orderBy($field, $sort) + public function orderBy($field, $sort = 'ASC') { if (count($this->orderBy) == 1 && $this->orderBy[0] == '') { + // Just set the initial index $this->orderBy[0] = $field; - $this->sortBy[0] = $sort; + $this->sortBy[0] = strtoupper($sort); } else { $this->orderBy[] = $field; - $this->sortBy[] = $sort; + $this->sortBy[] = strtoupper($sort); } return $this; diff --git a/src/QueryLogic.php b/src/QueryLogic.php index 2f275b4..0516fee 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -1,5 +1,6 @@ orderBy[$i] : $orderBy; - $sortBy = ($sortBy == null) ? $this->sortBy[$i] : $sortBy; - - if ($orderBy=='') + if ($this->orderBy[0] == '') { return false; } - $user_sort_function = function($a, $b) use ($orderBy, $sortBy, $i) { - - $propA = $a->field($orderBy); - $propB = $b->field($orderBy); - - - if (strnatcasecmp($propB, $propA) == strnatcasecmp($propA, $propB)) { - if (!isset($this->orderBy[$i + 1])) { - return 0; - } - // If they match and there are multiple orderBys, go deeper (recurse) - printf("going deeper %s %s\n", $i, $this->orderBy[$i + 1]); - $i = $i + 1; - return $user_sort_function($this->orderBy[$i], $this->sortBy[$i]); - } - - if ($sortBy == 'DESC') - { - return (strnatcasecmp($propB, $propA) < strnatcasecmp($propA, $propB)) ? -1 : 1; - } - else - { - return (strnatcasecmp($propA, $propB) < strnatcasecmp($propB, $propA)) ? -1 : 1; - } - - }; - - usort($this->documents, $user_sort_function); - + $sortlogic = new SortLogic($this->orderBy, $this->sortBy, 0); + usort($this->documents, [$sortlogic, 'sort']); } diff --git a/src/SortLogic.php b/src/SortLogic.php new file mode 100644 index 0000000..ef417e3 --- /dev/null +++ b/src/SortLogic.php @@ -0,0 +1,79 @@ +orderBy = $orderBy; + $this->sortDirection = $sortDirection; + $this->index = $index; + } + + /** + * Sorting callback + * + * @param Document $docA + * @param Document $docB + * @return return int (-1, 0, 1) + */ + public function sort($docA, $docB) + { + $propA = $docA->field($this->orderBy[$this->index]); + $propB = $docB->field($this->orderBy[$this->index]); + + if (strnatcasecmp($propA, $propB) == 0) + { + if (!isset($this->orderBy[$this->index + 1])) + { + return 0; + } + + // If they match and there are multiple orderBys, go deeper (recurse) + $sortlogic = new self($this->orderBy, $this->sortDirection, $this->index + 1); + return $sortlogic->sort($docA, $docB); + } + + if ($this->sortDirection[$this->index] == 'DESC') + { + return strnatcasecmp($propB, $propA); + } + else + { + return strnatcasecmp($propA, $propB); + } + } +} diff --git a/tests/QueryTest.php b/tests/QueryTest.php index 66fc4dc..8d10284 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -498,7 +498,7 @@ public function testSorting() } - public function testMultiOrderby() + public function prepareMultiOrderTestData() { $db = new \Filebase\Database([ 'dir' => __DIR__ . '/databases/users_orderbymult', @@ -507,7 +507,7 @@ public function testMultiOrderby() $db->flush(true); - $companies = ['Google'=>['CA', 150], 'Apple'=>['CA', 180], 'Microsoft'=>['WA', 120], 'Amex'=>['DC', 20], 'Hooli'=>['CA', 50], 'Amazon'=>['PA', 140]]; + $companies = ['Google'=>['CA', 150], 'Apple'=>['CA', 180], 'Microsoft'=>['WA', 120], 'Amex'=>['DC', 20], 'Hooli'=>['CA', 150], 'Amazon'=>['PA', 140]]; foreach ($companies as $company => $data) { $doc = $db->get(uniqid()); @@ -518,7 +518,26 @@ public function testMultiOrderby() $doc->save(); } - $test0 = $db->query()->orderBy('location', 'ASC')->results(); + return $db; + } + + public function testMultiOrderbyOneOnly() + { + $db = $this->prepareMultiOrderTestData(); + + $test1 = $db->query()->orderBy('location', 'asc')->results(); + $actual = array_map(function($doc) { + return $doc['name']; + }, $test1); + $expected = ['Google', 'Apple', 'Hooli', 'Amex', 'Amazon', 'Microsoft']; + $this->assertEquals($expected, $actual); + + $db->flush(true); + } + + public function testMultiOrderbyTwoAscAsc() + { + $db = $this->prepareMultiOrderTestData(); $test1 = $db->query()->orderBy('location', 'ASC')->orderBy('name', 'ASC')->results(); $actual = array_map(function($doc) { @@ -530,6 +549,47 @@ public function testMultiOrderby() $db->flush(true); } + public function testMultiOrderbyTwoDescAsc() + { + $db = $this->prepareMultiOrderTestData(); + + $test2 = $db->query()->orderBy('location', 'desc')->orderBy('name', 'ASC')->results(); + $actual = array_map(function($doc) { + return $doc['name']; + }, $test2); + $expected = ['Microsoft', 'Amazon', 'Amex', 'Apple', 'Google', 'Hooli']; + $this->assertEquals($expected, $actual); + + $db->flush(true); + } + + public function testMultiOrderbyTwoAscDesc() + { + $db = $this->prepareMultiOrderTestData(); + + $test3 = $db->query()->orderBy('location', 'ASC')->orderBy('name', 'DESC')->results(); + $actual = array_map(function($doc) { + return $doc['name']; + }, $test3); + $expected = ['Hooli', 'Google', 'Apple', 'Amex', 'Amazon', 'Microsoft']; + $this->assertEquals($expected, $actual); + + $db->flush(true); + } + + public function testMultiOrderbyThree() + { + $db = $this->prepareMultiOrderTestData(); + + $test4 = $db->query()->orderBy('location', 'ASC')->orderBy('rank.reviews', 'ASC')->orderBy('name')->results(); + $actual = array_map(function($doc) { + return $doc['name']; + }, $test4); + $expected = ['Google', 'Hooli', 'Apple', 'Amex', 'Amazon', 'Microsoft']; + $this->assertEquals($expected, $actual); + + $db->flush(true); + } //-------------------------------------------------------------------- From 40049fa91587bcef65ce10aeeffb9b8adcc8e217 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Thu, 21 Feb 2019 14:09:53 -0500 Subject: [PATCH 22/51] Updated test for the correct directory. --- tests/QueryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/QueryTest.php b/tests/QueryTest.php index d1a9911..78038ea 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1045,9 +1045,9 @@ public function testQueryFromCacheAfterSave() $db->flush(true); } public function testDeleteWhereMatchItemsWithCustomFilter() - { + { $db = new \Filebase\Database([ - 'dir' => 'path/to/users/users/test', + 'dir' => __DIR__.'/databases/deletefilter', ]); $db->flush(true); From 9fccaab355725282f43350edf78a9cd20a2e6eb9 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Thu, 21 Feb 2019 15:34:42 -0500 Subject: [PATCH 23/51] Updated readme and changelog [ci skip] --- CHANGELOG.md | 3 +++ README.md | 7 +++++-- src/Database.php | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a8ac76..ec9a5b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Change Log ========== +### 02/21/2019 - 1.0.22 +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/47) for deleting items with a custom filter. (this adds the `delete()` method on queries.) + ### 12/26/2018 - 1.0.21 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/30) for YAML format. diff --git a/README.md b/README.md index 1fc13db..db6e4ca 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,6 @@ if ($database->has('kingslayer')) // do some action } - // Need to find all the users that have a tag for "php" ? $users = $db->query()->where('tags','IN','php')->results(); @@ -379,13 +378,16 @@ echo $user['name']; // What about regex search? Finds emails within a field $users = $db->query()->where('email','REGEX','/[a-z\d._%+-]+@[a-z\d.-]+\.[a-z]{2,4}\b/i')->results(); - // Find all users that have gmail addresses and only returning their name and age fields (excluding the rest) $users = $db->query()->select('name,age')->where('email','LIKE','@gmail.com')->results(); // Instead of returning users, how about just count how many users are found. $totalUsers = $db->query()->where('email','LIKE','@gmail.com')->count(); +// Delete using custom filters (this will act like a bulk delete) +$db->query()->where('name','LIKE','john')->delete(function($item){ + return ($item->name == 'John' && $item->email == 'some@mail.com'); +}); ``` @@ -403,6 +405,7 @@ To run the query use `results()` or if you only want to return the first item us |`orWhere()` | `mixed` | see `where()`, this uses the logical `OR` | |`limit()` | `int` limit, `int` offset | How many documents to return, and offset | |`orderBy()` | `field` , `sort order` | Order documents by a specific field and order by `ASC` or `DESC` | +|`delete()` | `Closure` | Ability to Bulk-delete all items that match | The below **methods execute the query** and return results *(do not try to use them together)* diff --git a/src/Database.php b/src/Database.php index f6dcdfe..9a7c7ac 100644 --- a/src/Database.php +++ b/src/Database.php @@ -15,7 +15,7 @@ class Database * Stores the version of Filebase * use $db->getVersion() */ - const VERSION = '1.0.20'; + const VERSION = '1.0.22'; //-------------------------------------------------------------------- @@ -322,7 +322,7 @@ protected function read($name) $file = Filesystem::read( $this->config->dir . '/' - . Filesystem::validateName($name, $this->config->safe_filename) + . Filesystem::validateName($name, $this->config->safe_filename) . '.' . $format::getFileExtension() ); From 1a3beaf1cb5ed981131b311436b2790ad07800f0 Mon Sep 17 00:00:00 2001 From: faryar Date: Fri, 22 Feb 2019 21:42:30 +0330 Subject: [PATCH 24/51] add support call "Query::class" methods on database directly --- src/Database.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Database.php b/src/Database.php index 9a7c7ac..2974eb8 100644 --- a/src/Database.php +++ b/src/Database.php @@ -488,4 +488,17 @@ public function getConfig() return $this->config; } + public function __call($method,$args) + { + if(method_exists($this,$method)) + { + return $this->$method(...$args); + } + if(method_exists(Query::class,$method)) + { + return (new Query($this))->$method(...$args); + } + throw new \BadMethodCallException("method {$method} not found on 'Database::class' and 'Query::class'"); + } + } From 13e720a60a16dc11a6138206472e6a6b57a1fc41 Mon Sep 17 00:00:00 2001 From: faryar Date: Fri, 22 Feb 2019 21:43:37 +0330 Subject: [PATCH 25/51] add test for call query methods on database directly --- tests/DatabaseTest.php | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 0ec59c6..0febba8 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -258,4 +258,54 @@ public function testDatabaseSavingNotEncodableDocument() $doc->save(); } + public function test_Call_Queryclass_methods_on_database_without_query_method() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/saved', + 'cache' => true + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->save(); + } + + $results = $db->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + $result_from_cache = $db->where('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + + $this->assertEquals(10, count($results)); + $this->assertEquals(true, ($result_from_cache[0]->isCache())); + + $id = $result_from_cache[0]->getId(); + $id2 = $result_from_cache[1]->getId(); + + // Change the name + $result_from_cache[0]->name = 'Tim'; + $result_from_cache[0]->save(); + + $results = $db + ->where('name','=','John') + ->andWhere('email','==','john@example.com') + ->resultDocuments(); + + $this->assertEquals($id2, $results[0]->getId()); + $this->assertEquals('John', $results[0]->name); + + $db->flush(true); + } + public function test_must_return_exception_on_non_exist_method() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/saved', + 'cache' => true + ]); + + $this->expectException(\BadMethodCallException::class); + $results = $db->none('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); + } } From 089fec7c62f23ea2bd9c33301c25e36c2dbecf9a Mon Sep 17 00:00:00 2001 From: faryar Date: Fri, 22 Feb 2019 21:51:10 +0330 Subject: [PATCH 26/51] refactor --- src/Database.php | 69 ++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/src/Database.php b/src/Database.php index 2974eb8..7f921d1 100644 --- a/src/Database.php +++ b/src/Database.php @@ -96,26 +96,25 @@ public function findAll($include_documents = true, $data_only = false) $file_location = $this->config->dir.'/'; $all_items = Filesystem::getAllFiles($file_location, $file_extension); - if ($include_documents==true) + if (!$include_documents) { - $items = []; - - foreach($all_items as $a) - { - if ($data_only === true) - { - $items[] = $this->get($a)->getData(); - } - else - { - $items[] = $this->get($a); - } - } - - return $items; + return $all_items; } + $items = []; - return $all_items; + foreach($all_items as $a) + { + if ($data_only === true) + { + $items[] = $this->get($a)->getData(); + } + else + { + $items[] = $this->get($a); + } + } + + return $items; } @@ -283,10 +282,8 @@ public function save(Document $document, $wdata = '') return $document; } - else - { - return false; - } + + return false; } @@ -393,28 +390,24 @@ public function flush($confirm = false) throw new Exception("This database is set to be read-only. No modifications can be made."); } - if ($confirm===true) + if ($confirm!==true) { - $format = $this->config->format; - $documents = $this->findAll(false); - foreach($documents as $document) - { - Filesystem::delete($this->config->dir.'/'.$document.'.'.$format::getFileExtension()); - } + throw new Exception("Database Flush failed. You must send in TRUE to confirm action."); + } - if ($this->count() === 0) - { - return true; - } - else - { - throw new Exception("Could not delete all database files in ".$this->config->dir); - } + $format = $this->config->format; + $documents = $this->findAll(false); + foreach($documents as $document) + { + Filesystem::delete($this->config->dir.'/'.$document.'.'.$format::getFileExtension()); } - else + + if ($this->count() === 0) { - throw new Exception("Database Flush failed. You must send in TRUE to confirm action."); + return true; } + + throw new Exception("Could not delete all database files in ".$this->config->dir); } From ce06f29521ed052a7c42bdcddd6671709f2a3402 Mon Sep 17 00:00:00 2001 From: faryar Date: Fri, 22 Feb 2019 21:59:14 +0330 Subject: [PATCH 27/51] refactor --- src/Backup.php | 102 +++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/src/Backup.php b/src/Backup.php index d96872e..37bcb8e 100644 --- a/src/Backup.php +++ b/src/Backup.php @@ -157,21 +157,18 @@ public function rollback() */ protected function extract($source = '', $target = '') { - if (extension_loaded('zip')) + if (!extension_loaded('zip') && !file_exists($source)) { - if (file_exists($source)) - { - $zip = new \ZipArchive(); - if ($zip->open($source) === TRUE) - { - $zip->extractTo($target); - $zip->close(); - - return true; - } - } + return false; } + $zip = new \ZipArchive(); + if ($zip->open($source) === TRUE) + { + $zip->extractTo($target); + $zip->close(); + return true; + } return false; } @@ -187,50 +184,45 @@ protected function extract($source = '', $target = '') */ protected function zip($source = '', $target = '') { - if (extension_loaded('zip')) + if (!extension_loaded('zip') || !file_exists($source)) + { + return false; + } + + $zip = new \ZipArchive(); + if (!$zip->open($target, \ZIPARCHIVE::CREATE)) + { + $zip->addFromString(basename($source), file_get_contents($source)); + } + $source = realpath($source); + if (is_dir($source)) { - if (file_exists($source)) - { - $zip = new \ZipArchive(); - if ($zip->open($target, \ZIPARCHIVE::CREATE)) - { - $source = realpath($source); - if (is_dir($source)) - { - $iterator = new \RecursiveDirectoryIterator($source); - $iterator->setFlags(\RecursiveDirectoryIterator::SKIP_DOTS); - $files = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); - foreach ($files as $file) - { - $file = realpath($file); - - if (preg_match('|'.realpath($this->backupLocation).'|',$file)) - { - continue; - } - - if (is_dir($file)) - { - $zip->addEmptyDir(str_replace($source . '/', '', $file . '/')); - } - else if (is_file($file)) - { - $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file)); - } - } - - } - else if (is_file($source)) - { - $zip->addFromString(basename($source), file_get_contents($source)); - } - } - - return $zip->close(); - } - } - - return false; + $iterator = new \RecursiveDirectoryIterator($source); + $iterator->setFlags(\RecursiveDirectoryIterator::SKIP_DOTS); + $files = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); + foreach ($files as $file) + { + $file = realpath($file); + + if (preg_match('|'.realpath($this->backupLocation).'|',$file)) + { + continue; + } + + if (is_dir($file)) + { + $zip->addEmptyDir(str_replace($source . '/', '', $file . '/')); + } + else if (is_file($file)) + { + $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file)); + } + } + + } + + return $zip->close(); + } From 8050f6b8b7c3ef7e74032e2086dfbb49c59e84dd Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Fri, 22 Feb 2019 23:38:54 -0500 Subject: [PATCH 28/51] Updated changelog and readme [ci skip] --- CHANGELOG.md | 3 ++- README.md | 45 ++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec9a5b5..b8f4035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ Change Log ========== -### 02/21/2019 - 1.0.22 +### 02/23/2019 - 1.0.22 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/47) for deleting items with a custom filter. (this adds the `delete()` method on queries.) +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/48) for calling to the Query methods directly on the database class. ### 12/26/2018 - 1.0.21 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/30) for YAML format. diff --git a/README.md b/README.md index db6e4ca..d52574c 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,10 @@ if ($database->has('kingslayer')) } // Need to find all the users that have a tag for "php" ? -$users = $db->query()->where('tags','IN','php')->results(); +$users = $db->where('tags','IN','php')->results(); // Need to search for all the users who use @yahoo.com email addresses? -$users = $db->query()->where('email','LIKE','@yahoo.com')->results(); +$users = $db->where('email','LIKE','@yahoo.com')->results(); ``` @@ -333,59 +333,58 @@ Queries allow you to search **multiple documents** and return only the ones that If caching is enabled, queries will use `findAll()` and then cache results for the next run. +> Note: You no longer need to call `query()`, you can now call query methods directly on the database class. + ```php // Simple (equal to) Query // return all the users that are blocked. -$users = $db->query()->where(['status' => 'blocked'])->results(); +$users = $db->where(['status' => 'blocked'])->results(); // Stackable WHERE clauses // return all the users who are blocked, // AND have "php" within the tag array -$users = $db->query() - ->where('status','=','blocked') - ->andWhere('tag','IN','php') - ->results(); +$users = $db->where('status','=','blocked') + ->andWhere('tag','IN','php') + ->results(); // You can also use `.` dot delimiter to use on nested keys -$users = $db->query()->where('status.language.english','=','blocked')->results(); +$users = $db->where('status.language.english','=','blocked')->results(); // Limit Example: Same query as above, except we only want to limit the results to 10 -$users = $db->query()->where('status.language.english','=','blocked')->limit(10)->results(); +$users = $db->where('status.language.english','=','blocked')->limit(10)->results(); // Query LIKE Example: how about find all users that have a gmail account? -$usersWithGmail = $db->query()->where('email','LIKE','@gmail.com')->results(); +$usersWithGmail = $db->where('email','LIKE','@gmail.com')->results(); // OrderBy Example: From the above query, what if you want to order the results by nested array -$usersWithGmail = $db->query() - ->where('email','LIKE','@gmail.com') - ->orderBy('profile.name', 'ASC') - ->results(); +$usersWithGmail = $db->where('email','LIKE','@gmail.com') + ->orderBy('profile.name', 'ASC') + ->results(); // or just order the results by email address -$usersWithGmail = $db->query() - ->where('email','LIKE','@gmail.com') - ->orderBy('email', 'ASC') - ->results(); +$usersWithGmail = $db->where('email','LIKE','@gmail.com') + ->orderBy('email', 'ASC') + ->results(); // this will return the first user in the list based on ascending order of user name. -$user = $db->query()->orderBy('name', 'ASC')->first(); +$user = $db->orderBy('name', 'ASC')->first(); // print out the user name echo $user['name']; // What about regex search? Finds emails within a field -$users = $db->query()->where('email','REGEX','/[a-z\d._%+-]+@[a-z\d.-]+\.[a-z]{2,4}\b/i')->results(); +$users = $db->where('email','REGEX','/[a-z\d._%+-]+@[a-z\d.-]+\.[a-z]{2,4}\b/i')->results(); // Find all users that have gmail addresses and only returning their name and age fields (excluding the rest) -$users = $db->query()->select('name,age')->where('email','LIKE','@gmail.com')->results(); +$users = $db->select('name,age')->where('email','LIKE','@gmail.com')->results(); // Instead of returning users, how about just count how many users are found. -$totalUsers = $db->query()->where('email','LIKE','@gmail.com')->count(); +$totalUsers = $db->where('email','LIKE','@gmail.com')->count(); // Delete using custom filters (this will act like a bulk delete) -$db->query()->where('name','LIKE','john')->delete(function($item){ +$db->where('name','LIKE','john')->delete(function($item){ return ($item->name == 'John' && $item->email == 'some@mail.com'); }); From 2242961e9446336cd2178aea8c0b25a63d8d0070 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Fri, 22 Feb 2019 23:53:53 -0500 Subject: [PATCH 29/51] Updated readme and changelog [ci skip] --- CHANGELOG.md | 1 + README.md | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8f4035..863568e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Change Log ### 02/23/2019 - 1.0.22 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/47) for deleting items with a custom filter. (this adds the `delete()` method on queries.) * Merged [Pull Request](https://github.com/filebase/Filebase/pull/48) for calling to the Query methods directly on the database class. +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/45) for sorting by update/created at times (ability to fetch `__created_at` and `__updated_at`) ### 12/26/2018 - 1.0.21 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/30) for YAML format. diff --git a/README.md b/README.md index d52574c..5158a26 100644 --- a/README.md +++ b/README.md @@ -388,6 +388,11 @@ $db->where('name','LIKE','john')->delete(function($item){ return ($item->name == 'John' && $item->email == 'some@mail.com'); }); + +// ability to sort the results by created at or updated at times +$documents = $db->orderBy('__created_at', 'DESC')->results(); +$documents = $db->orderBy('__updated_at', 'DESC')->results(); + ``` To run the query use `results()` or if you only want to return the first item use `first()` From 3228dd638404e7f423982780943a7cf6be1cea12 Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Sat, 23 Feb 2019 10:17:51 -0600 Subject: [PATCH 30/51] Add documentation for update to orderBy --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 1fc13db..98c9922 100644 --- a/README.md +++ b/README.md @@ -370,6 +370,12 @@ $usersWithGmail = $db->query() ->orderBy('email', 'ASC') ->results(); +// OrderBy can be applied multiple times to perform a multi-sort +$usersWithGmail = $db->query() + ->where('email','LIKE','@gmail.com') + ->orderBy('last_name', 'ASC') + ->orderBy('email', 'ASC') + ->results(); // this will return the first user in the list based on ascending order of user name. $user = $db->query()->orderBy('name', 'ASC')->first(); From 0c7216cc9ecd7f26a32d02635ab2e9d5e115cf2d Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Sat, 23 Feb 2019 18:02:16 -0600 Subject: [PATCH 31/51] Slight update to README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 98c9922..54dec84 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ Filebase is simple by design, but has enough features for the more advanced. * File locking (on save) * Intuitive Method Naming - ## Installation Use [Composer](http://getcomposer.org/) to install package. From def58f7b4a0ce6287191e014ab8106e5eda80ca7 Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Sat, 23 Feb 2019 20:03:11 -0600 Subject: [PATCH 32/51] Update test on query orderby to account for difference change in sort between 5.6 and 7.x See 'Sort order of elements' here: http://php.net/manual/en/migration70.incompatible.php --- tests/QueryTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/QueryTest.php b/tests/QueryTest.php index d99ee84..031b3cc 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -525,11 +525,11 @@ public function testMultiOrderbyOneOnly() { $db = $this->prepareMultiOrderTestData(); - $test1 = $db->query()->orderBy('location', 'asc')->results(); + $test1 = $db->query()->orderBy('name', 'asc')->results(); $actual = array_map(function($doc) { return $doc['name']; }, $test1); - $expected = ['Google', 'Apple', 'Hooli', 'Amex', 'Amazon', 'Microsoft']; + $expected = ['Amazon', 'Amex', 'Apple', 'Google', 'Hooli', 'Microsoft']; $this->assertEquals($expected, $actual); $db->flush(true); From 20c9caa2ebf63b71281d27a2949cf30cb2dece94 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Sun, 24 Feb 2019 13:50:56 -0500 Subject: [PATCH 33/51] Updated changelog and updated readme [ci skip] --- CHANGELOG.md | 4 ++++ README.md | 12 +++++++++++- src/Database.php | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 863568e..b70bae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Change Log ========== +### 02/24/2019 - 1.0.23 +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/49) Added support for order by multiple columns +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/46) Added ability to query document ids (internal id) + ### 02/23/2019 - 1.0.22 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/47) for deleting items with a custom filter. (this adds the `delete()` method on queries.) * Merged [Pull Request](https://github.com/filebase/Filebase/pull/48) for calling to the Query methods directly on the database class. diff --git a/README.md b/README.md index b403a20..df62698 100644 --- a/README.md +++ b/README.md @@ -375,10 +375,15 @@ $usersWithGmail = $db->query() ->results(); // this will return the first user in the list based on ascending order of user name. -$user = $db->orderBy('name', 'ASC')->first(); +$user = $db->orderBy('name','ASC')->first(); // print out the user name echo $user['name']; +// You can also order multiple columns as such (stacking) +$orderMultiples = $db->orderBy('field1','ASC') + ->orderBy('field2','DESC') + ->results(); + // What about regex search? Finds emails within a field $users = $db->where('email','REGEX','/[a-z\d._%+-]+@[a-z\d.-]+\.[a-z]{2,4}\b/i')->results(); @@ -394,10 +399,15 @@ $db->where('name','LIKE','john')->delete(function($item){ }); +// GLOBAL VARIABLES + // ability to sort the results by created at or updated at times $documents = $db->orderBy('__created_at', 'DESC')->results(); $documents = $db->orderBy('__updated_at', 'DESC')->results(); +// search for items that match the (internal) id +$documents = $db->where('__id', 'IN', ['id1', 'id2'])->results(); + ``` To run the query use `results()` or if you only want to return the first item use `first()` diff --git a/src/Database.php b/src/Database.php index 7f921d1..7be2a65 100644 --- a/src/Database.php +++ b/src/Database.php @@ -15,7 +15,7 @@ class Database * Stores the version of Filebase * use $db->getVersion() */ - const VERSION = '1.0.22'; + const VERSION = '1.0.23'; //-------------------------------------------------------------------- @@ -282,7 +282,7 @@ public function save(Document $document, $wdata = '') return $document; } - + return false; } @@ -406,7 +406,7 @@ public function flush($confirm = false) { return true; } - + throw new Exception("Could not delete all database files in ".$this->config->dir); } From 9cd6ccfdc5fc543cfbe4ce8c17fb60b121e9b8b5 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Sun, 24 Feb 2019 14:14:28 -0500 Subject: [PATCH 34/51] Updated query delete method to allow delete of all items in query (making custom filter optional). --- src/Query.php | 84 ++++++++++----------------------------------- tests/QueryTest.php | 23 +++++++++---- 2 files changed, 35 insertions(+), 72 deletions(-) diff --git a/src/Query.php b/src/Query.php index 5d72f5b..3712a29 100644 --- a/src/Query.php +++ b/src/Query.php @@ -10,17 +10,12 @@ class Query extends QueryLogic protected $sortBy = ['ASC']; protected $orderBy = ['']; - /** * $documents * */ protected $documents = []; - - //-------------------------------------------------------------------- - - /** * ->select() * @@ -42,7 +37,6 @@ public function select($fields) return $this; } - /** * ->where() * @@ -54,10 +48,6 @@ public function where(...$arg) return $this; } - - //-------------------------------------------------------------------- - - /** * ->andWhere() * @@ -69,10 +59,6 @@ public function andWhere(...$arg) return $this; } - - //-------------------------------------------------------------------- - - /** * ->orWhere() * @@ -84,10 +70,6 @@ public function orWhere(...$arg) return $this; } - - //-------------------------------------------------------------------- - - /** * ->limit() * @@ -106,10 +88,6 @@ public function limit($limit, $offset = 0) return $this; } - - //-------------------------------------------------------------------- - - /** * ->orderBy() * @@ -128,10 +106,6 @@ public function orderBy($field, $sort = 'ASC') return $this; } - - //-------------------------------------------------------------------- - - /** * addPredicate * @@ -141,10 +115,6 @@ protected function addPredicate($logic,$arg) $this->predicate->add($logic, $arg); } - - //-------------------------------------------------------------------- - - /** * ->getDocuments() * @@ -155,10 +125,6 @@ public function getDocuments() return $this->documents; } - - //-------------------------------------------------------------------- - - /** * ->results() * @@ -175,10 +141,6 @@ public function results( $data_only = true ) return $this->resultDocuments(); } - - //-------------------------------------------------------------------- - - /** * ->resultDocuments() * @@ -188,10 +150,6 @@ public function resultDocuments() return parent::run()->getDocuments(); } - - //-------------------------------------------------------------------- - - /** * ->first() * @@ -210,10 +168,6 @@ public function first( $data_only = true ) return current($results); } - - //-------------------------------------------------------------------- - - /** * ->last() * @@ -232,9 +186,6 @@ public function last( $data_only = true ) return end($results); } - //-------------------------------------------------------------------- - - /** * ->count() * @@ -247,11 +198,6 @@ public function count() return count($results); } - - //-------------------------------------------------------------------- - - - /** * toArray * @@ -273,21 +219,29 @@ public function toArray() return $docs; } - - //-------------------------------------------------------------------- - - public function delete($input) + /** + * delete + * + * The ability to delete items using queries + * + * Delete by condition or delete all within clause + * + * @return void + */ + public function delete($input = null) { - $items=$this->resultDocuments(); - $condition=$input; + $items = $this->resultDocuments(); + $condition = $input; foreach($items as $item) { - if(is_object($input)) - { - $condition=$input($item); + if (is_object($input)) { + $condition = $input($item); + + if ($condition) { + $item->delete(); + } } - if($condition) - { + else { $item->delete(); } } diff --git a/tests/QueryTest.php b/tests/QueryTest.php index 4d18590..1589e4a 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -1136,11 +1136,14 @@ public function testQueryFromCacheAfterSave() $db->flush(true); } + + public function testDeleteWhereMatchItemsWithCustomFilter() { $db = new \Filebase\Database([ 'dir' => __DIR__.'/databases/deletefilter', ]); + $db->flush(true); $a=0; @@ -1154,20 +1157,26 @@ public function testDeleteWhereMatchItemsWithCustomFilter() $user->save(); $a++; } - $actual=$db->query()->results(); + + $actual = $db->results(); $this->assertCount(15,$actual); - $r=$db->query()->where('name','LIKE','john')->resultDocuments(); - $this->assertInstanceOf(Document::class, $r[0]); - $db->query()->where('name','LIKE','john')->delete(function($item){ + $r = $db->where('name','LIKE','john')->resultDocuments(); + $this->assertInstanceOf(Document::class, $r[0]); + $db->where('name','LIKE','john')->delete(function($item){ return $item->name=='0John'; - }); - $actual=$db->query()->where('name','LIKE','john')->resultDocuments(); + + $actual = $db->where('name','LIKE','john')->resultDocuments(); $this->assertCount(14,$actual); - $db->flush(true); + $db->where('name','LIKE','john')->delete(); + + $checkAgain = $db->where('name','LIKE','john')->resultDocuments(); + $this->assertCount(0,$checkAgain); + + $db->flush(true); } From b64f8afcea5167935253f00dd4aa745f8be5f047 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Sun, 24 Feb 2019 14:14:44 -0500 Subject: [PATCH 35/51] Updated changelog and readme [ci skip] --- CHANGELOG.md | 1 + README.md | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b70bae0..026e4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Change Log ### 02/24/2019 - 1.0.23 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/49) Added support for order by multiple columns * Merged [Pull Request](https://github.com/filebase/Filebase/pull/46) Added ability to query document ids (internal id) +* Added ability to use query `delete()` on all items that match the query (making the custom filter optional) ### 02/23/2019 - 1.0.22 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/47) for deleting items with a custom filter. (this adds the `delete()` method on queries.) diff --git a/README.md b/README.md index df62698..fdaede9 100644 --- a/README.md +++ b/README.md @@ -393,7 +393,11 @@ $users = $db->select('name,age')->where('email','LIKE','@gmail.com')->results(); // Instead of returning users, how about just count how many users are found. $totalUsers = $db->where('email','LIKE','@gmail.com')->count(); -// Delete using custom filters (this will act like a bulk delete) + +// You can delete all documents that match the query (BULK DELETE) +$db->where('name','LIKE','john')->delete(); + +// Delete all items that match query and match custom filter $db->where('name','LIKE','john')->delete(function($item){ return ($item->name == 'John' && $item->email == 'some@mail.com'); }); From e8474123baf1d78b5d53074c7be4bef08b4877c3 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Sun, 24 Feb 2019 14:15:25 -0500 Subject: [PATCH 36/51] Standardizing the comment blocks, cleaning up notes. (all classes) [ci skip] --- src/Backup.php | 42 ++-------------------- src/Cache.php | 35 ------------------- src/Config.php | 20 ----------- src/Database.php | 85 ++++++--------------------------------------- src/Document.php | 85 --------------------------------------------- src/Filesystem.php | 20 ----------- src/Format/Json.php | 13 ------- src/Format/Yaml.php | 13 ------- src/Predicate.php | 15 -------- src/QueryLogic.php | 29 ---------------- src/Validate.php | 21 ----------- 11 files changed, 12 insertions(+), 366 deletions(-) diff --git a/src/Backup.php b/src/Backup.php index 37bcb8e..57ae5e9 100644 --- a/src/Backup.php +++ b/src/Backup.php @@ -12,10 +12,6 @@ class Backup */ protected $backupLocation; - - //-------------------------------------------------------------------- - - /** * $config * @@ -24,10 +20,6 @@ class Backup */ protected $config; - - //-------------------------------------------------------------------- - - /** * $database * @@ -35,10 +27,6 @@ class Backup */ protected $database; - - //-------------------------------------------------------------------- - - /** * __construct * @@ -63,10 +51,6 @@ public function __construct($backupLocation = '', Database $database) } } - - //-------------------------------------------------------------------- - - /** * save() * @@ -84,10 +68,6 @@ public function create() throw new \Exception('Error backing up database.'); } - - //-------------------------------------------------------------------- - - /** * find() * @@ -109,10 +89,6 @@ public function find() return $backups; } - - //-------------------------------------------------------------------- - - /** * clean() * @@ -124,10 +100,6 @@ public function clean() return array_map('unlink', glob(realpath($this->backupLocation)."/*.zip")); } - - //-------------------------------------------------------------------- - - /** * rollback() * @@ -144,10 +116,6 @@ public function rollback() return $this->extract($restore, $this->config->dir); } - - //-------------------------------------------------------------------- - - /** * extract() * @@ -172,10 +140,6 @@ protected function extract($source = '', $target = '') return false; } - - //-------------------------------------------------------------------- - - /** * zip() * @@ -218,13 +182,11 @@ protected function zip($source = '', $target = '') $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file)); } } - + } return $zip->close(); - - } - + } } diff --git a/src/Cache.php b/src/Cache.php index 47090f3..7eaa710 100644 --- a/src/Cache.php +++ b/src/Cache.php @@ -26,9 +26,6 @@ class Cache */ protected $key; - - //-------------------------------------------------------------------- - /** * __construct() * @@ -44,10 +41,6 @@ public function __construct(Database $database) ]); } - - //-------------------------------------------------------------------- - - /** * setKey() * @@ -60,10 +53,6 @@ public function setKey($key) $this->key = md5($key); } - - //-------------------------------------------------------------------- - - /** * getKey() * @@ -73,10 +62,6 @@ public function getKey() return $this->key; } - - //-------------------------------------------------------------------- - - /** * flush() * @@ -86,10 +71,6 @@ public function flush() $this->cache_database->flush(true); } - - //-------------------------------------------------------------------- - - /** * expired() * @@ -106,10 +87,6 @@ public function expired($time) return true; } - - //-------------------------------------------------------------------- - - /** * getDocuments() * @@ -125,10 +102,6 @@ public function getDocuments($documents) return $d; } - - //-------------------------------------------------------------------- - - /** * get() * @@ -155,10 +128,6 @@ public function get() return $this->getDocuments($cache_doc->toArray()); } - - //-------------------------------------------------------------------- - - /** * store() * @@ -173,8 +142,4 @@ public function store($data) return $this->cache_database->get( $this->getKey() )->set($data)->save(); } - - //-------------------------------------------------------------------- - - } diff --git a/src/Config.php b/src/Config.php index 304f931..56c2d3b 100644 --- a/src/Config.php +++ b/src/Config.php @@ -11,7 +11,6 @@ class Config */ public $dir = __DIR__; - /** * $format * Format Class @@ -19,7 +18,6 @@ class Config */ public $format = \Filebase\Format\Json::class; - /** * $cache * Caching for queries @@ -28,7 +26,6 @@ class Config */ public $cache = true; - /** * $cache_time * When should cache be cleared? @@ -37,7 +34,6 @@ class Config */ public $cache_expires = 1800; - /** * $safe_filename * (if true) Be sure to automatically change the file name if it does not fit validation @@ -47,7 +43,6 @@ class Config */ public $safe_filename = true; - /** * $read_only * (if true) We will not attempt to create the database directory or allow the user to create anything @@ -57,7 +52,6 @@ class Config */ public $read_only = false; - /** * $backupLocation * The location to store backups @@ -66,7 +60,6 @@ class Config */ public $backupLocation = ''; - /** * $pretty * @@ -77,17 +70,12 @@ class Config */ public $pretty = true; - /** * $validate * */ public $validate = []; - - //-------------------------------------------------------------------- - - /** * __construct * @@ -110,10 +98,6 @@ public function __construct($config) $this->validateFormatClass(); } - - //-------------------------------------------------------------------- - - /** * format * @@ -138,8 +122,4 @@ protected function validateFormatClass() throw new \Exception('Filebase Error: Format Class must be an instance of Filebase\Format\FormatInterface'); } } - - - //-------------------------------------------------------------------- - } diff --git a/src/Database.php b/src/Database.php index 7be2a65..559b8cb 100644 --- a/src/Database.php +++ b/src/Database.php @@ -17,9 +17,6 @@ class Database */ const VERSION = '1.0.23'; - - //-------------------------------------------------------------------- - /** * $config * @@ -28,7 +25,6 @@ class Database */ protected $config; - /** * Database constructor. * @@ -57,10 +53,6 @@ public function __construct(array $config = []) } } - - //-------------------------------------------------------------------- - - /** * version * @@ -73,10 +65,6 @@ public function version() return self::VERSION; } - - //-------------------------------------------------------------------- - - /** * findAll() * @@ -117,10 +105,6 @@ public function findAll($include_documents = true, $data_only = false) return $items; } - - //-------------------------------------------------------------------- - - /** * get * @@ -148,10 +132,6 @@ public function get($id) return $document; } - - //-------------------------------------------------------------------- - - /** * has * @@ -169,10 +149,6 @@ public function has($id) return $record ? true : false; } - - //-------------------------------------------------------------------- - - /** * backup * @@ -190,10 +166,6 @@ public function backup($location = '') return new Backup($this->config->backupLocation, $this); } - - //-------------------------------------------------------------------- - - /** * set * @@ -216,10 +188,6 @@ public function set(Document $document, $data) return $document; } - - //-------------------------------------------------------------------- - - /** * count * @@ -231,10 +199,6 @@ public function count() return count($this->findAll(false)); } - - //-------------------------------------------------------------------- - - /** * @param Document $document * @param string $wdata @@ -286,10 +250,6 @@ public function save(Document $document, $wdata = '') return false; } - - //-------------------------------------------------------------------- - - /** * query * @@ -300,10 +260,6 @@ public function query() return new Query($this); } - - //-------------------------------------------------------------------- - - /** * Read and return Document from filesystem by name. * If doesn't exists return new empty Document. @@ -330,10 +286,6 @@ protected function read($name) return null; } - - //-------------------------------------------------------------------- - - /** * delete * @@ -356,9 +308,6 @@ public function delete(Document $document) return $d; } - - //-------------------------------------------------------------------- - /** * truncate * @@ -371,10 +320,6 @@ public function truncate() return $this->flush(true); } - - //-------------------------------------------------------------------- - - /** * flush * @@ -410,10 +355,6 @@ public function flush($confirm = false) throw new Exception("Could not delete all database files in ".$this->config->dir); } - - //-------------------------------------------------------------------- - - /** * flushCache * @@ -428,10 +369,6 @@ public function flushCache() } } - - //-------------------------------------------------------------------- - - /** * toArray * @@ -443,10 +380,6 @@ public function toArray(Document $document) return $this->objectToArray( $document->getData() ); } - - //-------------------------------------------------------------------- - - /** * objectToArray * @@ -467,10 +400,6 @@ public function objectToArray($obj) return $arr; } - - //-------------------------------------------------------------------- - - /** * getConfig * @@ -481,16 +410,22 @@ public function getConfig() return $this->config; } + /** + * __call + * + * Magic method to give us access to query methods on db class + * + */ public function __call($method,$args) { - if(method_exists($this,$method)) - { + if(method_exists($this,$method)) { return $this->$method(...$args); } - if(method_exists(Query::class,$method)) - { + + if(method_exists(Query::class,$method)) { return (new Query($this))->$method(...$args); } + throw new \BadMethodCallException("method {$method} not found on 'Database::class' and 'Query::class'"); } diff --git a/src/Document.php b/src/Document.php index 53513ad..0fcf27d 100644 --- a/src/Document.php +++ b/src/Document.php @@ -25,10 +25,6 @@ public function __construct($database) $this->__database = $database; } - - //-------------------------------------------------------------------- - - /** * saveAs * @@ -47,10 +43,6 @@ public function saveAs() return $data; } - - //-------------------------------------------------------------------- - - /** * save() * @@ -66,10 +58,6 @@ public function save($data = '') return $this->__database->save($this, $data); } - - //-------------------------------------------------------------------- - - /** * delete * @@ -82,10 +70,6 @@ public function delete() return $this->__database->delete($this); } - - //-------------------------------------------------------------------- - - /** * set * @@ -95,10 +79,6 @@ public function set($data) return $this->__database->set($this, $data); } - - //-------------------------------------------------------------------- - - /** * toArray * @@ -108,10 +88,6 @@ public function toArray() return $this->__database->toArray($this); } - - //-------------------------------------------------------------------- - - /** * __set * @@ -121,10 +97,6 @@ public function __set($name, $value) $this->data[$name] = $value; } - - //-------------------------------------------------------------------- - - /** * __get * @@ -139,10 +111,6 @@ public function &__get($name) return $this->data[$name]; } - - //-------------------------------------------------------------------- - - /** * __isset * @@ -152,10 +120,6 @@ public function __isset($name) return isset($this->data[$name]); } - - //-------------------------------------------------------------------- - - /** * __unset * @@ -181,10 +145,6 @@ public function filter($field = 'data', $paramOne = '', $paramTwo = '') return $this->customFilter($field, $paramOne, $paramTwo); } - - //-------------------------------------------------------------------- - - /** * customFilter * @@ -235,10 +195,6 @@ public function customFilter($field = 'data', $paramOne = '', $paramTwo = '') } - - //-------------------------------------------------------------------- - - /** * getDatabase * @@ -249,10 +205,6 @@ public function getDatabase() return $this->__database; } - - //-------------------------------------------------------------------- - - /** * getId * @@ -263,10 +215,6 @@ public function getId() return $this->__id; } - - //-------------------------------------------------------------------- - - /** * getData * @@ -277,10 +225,6 @@ public function getData() return $this->data; } - - //-------------------------------------------------------------------- - - /** * setId * @@ -293,10 +237,6 @@ public function setId($id) return $this; } - - //-------------------------------------------------------------------- - - /** * setCache * @@ -309,10 +249,6 @@ public function setFromCache($cache = true) return $this; } - - //-------------------------------------------------------------------- - - /** * isCache * @@ -322,11 +258,6 @@ public function isCache() return $this->__cache; } - - - //-------------------------------------------------------------------- - - /** * createdAt * @@ -350,10 +281,6 @@ public function createdAt($format = 'Y-m-d H:i:s') return $this->__created_at; } - - //-------------------------------------------------------------------- - - /** * updatedAt * @@ -377,10 +304,6 @@ public function updatedAt($format = 'Y-m-d H:i:s') return $this->__updated_at; } - - //-------------------------------------------------------------------- - - /** * setCreatedAt * @@ -393,10 +316,6 @@ public function setCreatedAt($created_at) return $this; } - - //-------------------------------------------------------------------- - - /** * setuUpdatedAt * @@ -409,10 +328,6 @@ public function setUpdatedAt($updated_at) return $this; } - - //-------------------------------------------------------------------- - - /** * field * diff --git a/src/Filesystem.php b/src/Filesystem.php index de16f24..307358d 100644 --- a/src/Filesystem.php +++ b/src/Filesystem.php @@ -23,11 +23,6 @@ public static function read($path) return $contents; } - - - //-------------------------------------------------------------------- - - /** * Writes data to the filesystem. * @@ -53,10 +48,6 @@ public static function write($path, $contents) return $result !== false; } - - //-------------------------------------------------------------------- - - /** * delete * @@ -73,10 +64,6 @@ public static function delete($path) return unlink($path); } - - //-------------------------------------------------------------------- - - /** * Validates the name of the file to ensure it can be stored in the * filesystem. @@ -107,10 +94,6 @@ public static function validateName($name, $safe_filename) return $name; } - - //-------------------------------------------------------------------- - - /** * Get an array containing the path of all files in this repository * @@ -128,7 +111,4 @@ public static function getAllFiles($path = '',$ext = 'json') return $files; } - - //-------------------------------------------------------------------- - } diff --git a/src/Format/Json.php b/src/Format/Json.php index 337ed38..6642208 100644 --- a/src/Format/Json.php +++ b/src/Format/Json.php @@ -11,10 +11,6 @@ public static function getFileExtension() return 'json'; } - - //-------------------------------------------------------------------- - - /** * @param array $data * @param bool $pretty @@ -41,10 +37,6 @@ public static function encode($data = [], $pretty = true) return $encoded; } - - //-------------------------------------------------------------------- - - /** * @param $data * @return mixed @@ -65,9 +57,4 @@ public static function decode($data) return $decoded; } - - - //-------------------------------------------------------------------- - - } diff --git a/src/Format/Yaml.php b/src/Format/Yaml.php index e43bc8c..10793ea 100644 --- a/src/Format/Yaml.php +++ b/src/Format/Yaml.php @@ -12,10 +12,6 @@ public static function getFileExtension() return 'yaml'; } - - //-------------------------------------------------------------------- - - /** * @param array $data * @param bool $pretty @@ -28,10 +24,6 @@ public static function encode($data = [], $pretty = true) return $encoded; } - - //-------------------------------------------------------------------- - - /** * @param $data * @return mixed @@ -42,9 +34,4 @@ public static function decode($data) $decoded = YamlParser::parse($data); return $decoded; } - - - //-------------------------------------------------------------------- - - } diff --git a/src/Predicate.php b/src/Predicate.php index 02071f1..2d15ed5 100644 --- a/src/Predicate.php +++ b/src/Predicate.php @@ -34,10 +34,6 @@ class Predicate */ protected $predicates = []; - - //-------------------------------------------------------------------- - - /** * add * @@ -82,9 +78,6 @@ public function add($logic,$arg) $this->predicates[$logic][] = $arg; } - - //-------------------------------------------------------------------- - /** * formatWhere * @@ -94,10 +87,6 @@ protected function formatWhere($key, $value) return [$key,'==',$value]; } - - //-------------------------------------------------------------------- - - /** * get * @@ -106,8 +95,4 @@ public function get() { return array_filter($this->predicates); } - - - //-------------------------------------------------------------------- - } diff --git a/src/QueryLogic.php b/src/QueryLogic.php index 0516fee..53e1c38 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -12,7 +12,6 @@ class QueryLogic */ protected $database; - /** * $predicate * @@ -28,10 +27,6 @@ class QueryLogic */ protected $cache = false; - - //-------------------------------------------------------------------- - - /** * __construct * @@ -47,10 +42,6 @@ public function __construct(Database $database) } } - - //-------------------------------------------------------------------- - - /** * run * @@ -122,10 +113,6 @@ public function run() return $this; } - - //-------------------------------------------------------------------- - - /** * filter * @@ -167,10 +154,6 @@ protected function filter($documents, $predicates) return $results; } - - //-------------------------------------------------------------------- - - /** * offsetLimit * @@ -183,10 +166,6 @@ protected function offsetLimit() } } - - //-------------------------------------------------------------------- - - /** * sort * @@ -202,10 +181,6 @@ protected function sort() usort($this->documents, [$sortlogic, 'sort']); } - - //-------------------------------------------------------------------- - - /** * match * @@ -252,8 +227,4 @@ public function match($document, $field, $operator, $value) } - - //-------------------------------------------------------------------- - - } diff --git a/src/Validate.php b/src/Validate.php index 15d2b59..5d29ae9 100644 --- a/src/Validate.php +++ b/src/Validate.php @@ -19,10 +19,6 @@ public static function valid(Document $object) return true; } - - //-------------------------------------------------------------------- - - /** * getValidateRules * @@ -34,10 +30,6 @@ public static function getValidateRules(Document $object) return $object->getDatabase()->getConfig()->validate; } - - //-------------------------------------------------------------------- - - /** * validateLoop * @@ -62,10 +54,6 @@ protected static function validateLoop($document,$object,$rules) } } - - //-------------------------------------------------------------------- - - /** * validateRules * @@ -104,10 +92,6 @@ protected static function validateRules($document,$key,$rules,$object) return $object; } - - //-------------------------------------------------------------------- - - /** * checkType * @@ -152,9 +136,4 @@ protected static function checkType($variable, $type) return false; } - - - //-------------------------------------------------------------------- - - } From d7630c4c7ff9feaae5cbfd4f2a5d862188964db0 Mon Sep 17 00:00:00 2001 From: faryar Date: Mon, 25 Feb 2019 01:46:19 +0330 Subject: [PATCH 37/51] fix bug #41 "results() returns document instead of array #41" --- src/QueryLogic.php | 40 ++++++++++++++++++++++++---------------- tests/DatabaseTest.php | 30 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/src/QueryLogic.php b/src/QueryLogic.php index 53e1c38..e573d86 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -42,6 +42,29 @@ public function __construct(Database $database) } } + private function loadDocuments() + { + $predicates = $this->predicate->get(); + + if ($this->cache===false) + { + $this->documents = $this->database->findAll(true,false); + return $this; + } + + $this->cache->setKey(json_encode($predicates)); + + if ($cached_documents = $this->cache->get()) + { + $this->documents = $cached_documents; + + $this->sort(); + $this->offsetLimit(); + return $this; + } + $this->documents = $this->database->findAll(true,false); + return $this; + } /** * run * @@ -57,22 +80,7 @@ public function run() $predicates = 'findAll'; } - if ($this->cache !== false) - { - $this->cache->setKey(json_encode($predicates)); - - if ($cached_documents = $this->cache->get()) - { - $this->documents = $cached_documents; - - $this->sort(); - $this->offsetLimit(); - - return $this; - } - } - - $this->documents = $this->database->findAll(true,false); + $this->loadDocuments(); if ($predicates !== 'findAll') { diff --git a/tests/DatabaseTest.php b/tests/DatabaseTest.php index 0febba8..e187e71 100644 --- a/tests/DatabaseTest.php +++ b/tests/DatabaseTest.php @@ -308,4 +308,34 @@ public function test_must_return_exception_on_non_exist_method() $this->expectException(\BadMethodCallException::class); $results = $db->none('name','=','John')->andWhere('email','==','john@example.com')->resultDocuments(); } + /** + * based on issue #41 + * results() returns document instead of array #41 + */ + public function test_must_return_array_on_select_an_culomn_from_cache() + { + $db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases/saved', + 'cache' => true + ]); + + $db->flush(true); + + for ($x = 1; $x <= 10; $x++) + { + $user = $db->get(uniqid()); + $user->name = 'John'; + $user->email = 'john@example.com'; + $user->save(); + } + + $db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); + $result_from_cache = $db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); + + $this->assertCount(10,$result_from_cache); + $this->assertEquals(['email'=>'john@example.com'],$result_from_cache[0]); + $this->assertInternalType('array', $result_from_cache[0]); + $this->assertInternalType('string', $result_from_cache[0]['email']); + $db->flush(true); + } } From b660650472362e45f78d97cb395f09889196d164 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Sun, 24 Feb 2019 17:55:23 -0500 Subject: [PATCH 38/51] Updated changelog and minor comment block updates. --- CHANGELOG.md | 3 +++ src/Database.php | 2 +- src/QueryLogic.php | 7 ++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 026e4b2..856a4e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Change Log ========== +### 02/24/2019 - 1.0.24 +* Merged [Pull Request](https://github.com/filebase/Filebase/pull/50) Fixed [bug](https://github.com/filebase/Filebase/issues/41) returning unexpected results. + ### 02/24/2019 - 1.0.23 * Merged [Pull Request](https://github.com/filebase/Filebase/pull/49) Added support for order by multiple columns * Merged [Pull Request](https://github.com/filebase/Filebase/pull/46) Added ability to query document ids (internal id) diff --git a/src/Database.php b/src/Database.php index 559b8cb..40b189b 100644 --- a/src/Database.php +++ b/src/Database.php @@ -15,7 +15,7 @@ class Database * Stores the version of Filebase * use $db->getVersion() */ - const VERSION = '1.0.23'; + const VERSION = '1.0.24'; /** * $config diff --git a/src/QueryLogic.php b/src/QueryLogic.php index e573d86..0d97c4f 100644 --- a/src/QueryLogic.php +++ b/src/QueryLogic.php @@ -42,6 +42,10 @@ public function __construct(Database $database) } } + /** + * loadDocuments + * + */ private function loadDocuments() { $predicates = $this->predicate->get(); @@ -60,11 +64,12 @@ private function loadDocuments() $this->sort(); $this->offsetLimit(); - return $this; + return $this; } $this->documents = $this->database->findAll(true,false); return $this; } + /** * run * From efe82dc49069a4f67603c27d50682ad160b5fdd3 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Wed, 26 Jun 2019 15:02:39 -0400 Subject: [PATCH 39/51] Updated composer (minor change) --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 13a3e3b..fd12390 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { "description": "A Simple but Powerful Flat File Database Storage.", "keywords": ["filebase", "key-value","file-files", "flat", "file", "database", "document", "flat-file", "serverless"], - "name": "filebase/filebase", - "homepage": "https://github.com/filebase/Filebase", + "name": "tmarois/filebase", + "homepage": "https://github.com/tmarois/Filebase", "type": "package", "licence": "MIT", From 6f436e3eb40a0f4702d5544f7f1bf64a07b4c238 Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Wed, 26 Jun 2019 15:07:12 -0400 Subject: [PATCH 40/51] Updated readme [ci skip] --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index fdaede9..e82720e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Filebase -[![Build Status](https://travis-ci.org/filebase/Filebase.svg?branch=1.0)](https://travis-ci.org/filebase/Filebase) [![Coverage Status](https://coveralls.io/repos/github/filebase/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/filebase/Filebase?branch=1.0) [![Slack](http://timothymarois.com/a/slack-02.svg)](https://join.slack.com/t/basephp/shared_invite/enQtNDI0MzQyMDE0MDAwLWU3Nzg0Yjk4MjM0OWVmZDZjMjEyYWE2YjA1ODFhNjI2MzI3MjAyOTIyOTRkMmVlNWNhZWYzMTIwZDJlOWQ2ZTA) +[![Build Status](https://travis-ci.org/tmarois/Filebase.svg?branch=1.0)](https://travis-ci.org/tmarois/Filebase) [![Coverage Status](https://coveralls.io/repos/github/tmarois/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/tmarois/Filebase?branch=1.0) [![Slack](http://timothymarois.com/a/slack-02.svg)](https://join.slack.com/t/basephp/shared_invite/enQtNDI0MzQyMDE0MDAwLWU3Nzg0Yjk4MjM0OWVmZDZjMjEyYWE2YjA1ODFhNjI2MzI3MjAyOTIyOTRkMmVlNWNhZWYzMTIwZDJlOWQ2ZTA) -A Simple but Powerful Flat File Database Storage. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](https://github.com/filebase/Filebase#2-formatting) the way you like). +A Simple but Powerful Flat File Database Storage. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](README.md#2-formatting) the way you like). You can even modify the raw data within the files themselves without ever needing to use the API. And even better you can put all your files in **version control** and pass them to your team without having out-of-sync SQL databases. @@ -17,12 +17,12 @@ Works with **PHP 5.6** and **PHP 7+** Filebase is simple by design, but has enough features for the more advanced. * Key/Value and Array-based Data Storing -* [Querying data](https://github.com/filebase/Filebase#8-queries) -* [Custom filters](https://github.com/filebase/Filebase#7-custom-filters) -* [Caching](https://github.com/filebase/Filebase#9-caching) (queries) -* [Database Backups](https://github.com/filebase/Filebase#10-database-backups) -* [Formatting](https://github.com/filebase/Filebase#2-formatting) (encode/decode) -* [Validation](https://github.com/filebase/Filebase#6-validation-optional) (on save) +* [Querying data](README.md#8-queries) +* [Custom filters](README.md#7-custom-filters) +* [Caching](README.md#9-caching) (queries) +* [Database Backups](README.md#10-database-backups) +* [Formatting](README.md#2-formatting) (encode/decode) +* [Validation](README.md#6-validation-optional) (on save) * CRUD (method APIs) * File locking (on save) * Intuitive Method Naming @@ -106,8 +106,8 @@ $db = new \Filebase\Database([ |`dir` |string |current directory |The directory where the database files are stored. | |`backupLocation` |string |current directory (`/backups`) |The directory where the backup zip files will be stored. | |`format` |object |`\Filebase\Format\Json` |The format class used to encode/decode data | -|`validate` |array | |Check [Validation Rules](https://github.com/filebase/Filebase#6-validation-optional) for more details | -|`cache` |bool |true |Stores [query](https://github.com/filebase/Filebase#8-queries) results into cache for faster loading. | +|`validate` |array | |Check [Validation Rules](README.md#6-validation-optional) for more details | +|`cache` |bool |true |Stores [query](README.md#8-queries) results into cache for faster loading. | |`cache_expire` |int |1800 |How long caching will last (in seconds) | |`pretty` |bool |true |Store the data for human readability? Pretty Print | |`safe_filename` |bool |true |Automatically converts the file name to a valid name (added: 1.0.13) | @@ -157,7 +157,7 @@ $item = $db->get($userId); |`updatedAt()` | Document was updated (default Y-m-d H:i:s) | |`field()` | You can also use `.` dot delimiter to find values from nested arrays | |`isCache()` | (true/false) if the current document is loaded from cache | -|`filter()` | Refer to the [Custom Filters](https://github.com/filebase/Filebase#7-custom-filters) | +|`filter()` | Refer to the [Custom Filters](README.md#7-custom-filters) | Example: @@ -219,15 +219,15 @@ Here is a list of methods you can use on the database class. |Method|Details| |---|---| |`version()` | Current version of your Filebase library | -|`get($id)` | Refer to [get()](https://github.com/filebase/Filebase#3-get-and-methods) | +|`get($id)` | Refer to [get()](README.md#3-get-and-methods) | |`has($id)` | Check if a record exist returning true/false | |`findAll()` | Returns all documents in database | |`count()` | Number of documents in database | |`flush(true)` | Deletes all documents. | |`flushCache()` | Clears all the cache | |`truncate()` | Deletes all documents. Alias of `flush(true)` | -|`query()` | Refer to the [Queries](https://github.com/filebase/Filebase#8-queries) | -|`backup()` | Refer to the [Backups](https://github.com/filebase/Filebase#10-database-backups) | +|`query()` | Refer to the [Queries](README.md#8-queries) | +|`backup()` | Refer to the [Backups](README.md#10-database-backups) | Examples From 2801db9d705ef10afb12fd4f27cca36ff8865aec Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Wed, 26 Jun 2019 15:23:49 -0400 Subject: [PATCH 41/51] Update readme for composer require [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e82720e..a87496e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Filebase is simple by design, but has enough features for the more advanced. Use [Composer](http://getcomposer.org/) to install package. -Run `composer require filebase/filebase:^1.0` +Run `composer require tmarois/filebase:^1.0` If you do not want to use composer, download the files, and include it within your application, it does not have any dependencies, you will just need to keep it updated with any future releases. From f369cfb0e5727552f717999f719c8643a686484e Mon Sep 17 00:00:00 2001 From: Timothy Marois Date: Wed, 24 Feb 2021 13:39:19 -0500 Subject: [PATCH 42/51] Updated readme with discord invite link --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a87496e..41c324c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Filebase -[![Build Status](https://travis-ci.org/tmarois/Filebase.svg?branch=1.0)](https://travis-ci.org/tmarois/Filebase) [![Coverage Status](https://coveralls.io/repos/github/tmarois/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/tmarois/Filebase?branch=1.0) [![Slack](http://timothymarois.com/a/slack-02.svg)](https://join.slack.com/t/basephp/shared_invite/enQtNDI0MzQyMDE0MDAwLWU3Nzg0Yjk4MjM0OWVmZDZjMjEyYWE2YjA1ODFhNjI2MzI3MjAyOTIyOTRkMmVlNWNhZWYzMTIwZDJlOWQ2ZTA) +[![Build Status](https://travis-ci.org/tmarois/Filebase.svg?branch=1.0)](https://travis-ci.org/tmarois/Filebase) [![Coverage Status](https://coveralls.io/repos/github/tmarois/Filebase/badge.svg?branch=1.0)](https://coveralls.io/github/tmarois/Filebase?branch=1.0) + +[Join Discord](https://discord.gg/kywDsDnJ6C) – For support, updates and collaboration. A Simple but Powerful Flat File Database Storage. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](README.md#2-formatting) the way you like). From db19fc21dcc53ea63362f1dc2d7cbae06c35ed9d Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 18:49:03 +0100 Subject: [PATCH 43/51] New updated version - Encryption was added to project --- composer.json | 3 +- src/Config.php | 7 +++++ src/Database.php | 10 +++---- src/Encrypter.php | 49 +++++++++++++++++++++++++++++++ src/Filesystem.php | 55 +++++++++++++++++++++++++++++++---- tests/EncryptionTest.php | 16 ++++++++++ tests/encrypter/keys/test.key | 1 + 7 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 src/Encrypter.php create mode 100644 tests/EncryptionTest.php create mode 100644 tests/encrypter/keys/test.key diff --git a/composer.json b/composer.json index fd12390..102cc36 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ ], "require": { - "php": ">=5.6" + "php": ">=5.6", + "paragonie/halite": "5" }, "require-dev": { diff --git a/src/Config.php b/src/Config.php index 56c2d3b..60baf48 100644 --- a/src/Config.php +++ b/src/Config.php @@ -76,6 +76,13 @@ class Config */ public $validate = []; + /** + * $encryption + * + * Contains all encryption options + */ + public $encryption; + /** * __construct * diff --git a/src/Database.php b/src/Database.php index 40b189b..7f5ce0f 100644 --- a/src/Database.php +++ b/src/Database.php @@ -24,7 +24,6 @@ class Database * \Filebase\Config */ protected $config; - /** * Database constructor. * @@ -144,7 +143,7 @@ public function get($id) public function has($id) { $format = $this->config->format; - $record = Filesystem::read( $this->config->dir.'/'.Filesystem::validateName($id, $this->config->safe_filename).'.'.$format::getFileExtension() ); + $record = Filesystem::read( $this->config->dir.'/'.Filesystem::validateName($id, $this->config->safe_filename).'.'.$format::getFileExtension(), $this->config->encryption); return $record ? true : false; } @@ -226,7 +225,7 @@ public function save(Document $document, $wdata = '') $document->setCreatedAt($created); } - if (!Filesystem::read($file_location) || $created==false) + if (!Filesystem::read($file_location, $this->config->encryption) || $created==false) { $document->setCreatedAt(time()); } @@ -240,7 +239,7 @@ public function save(Document $document, $wdata = '') throw new SavingException("Can not encode document.", 0, $e); } - if (Filesystem::write($file_location, $data)) + if (Filesystem::write($file_location, $data, $this->config->encryption)) { $this->flushCache(); @@ -276,7 +275,8 @@ protected function read($name) $file = Filesystem::read( $this->config->dir . '/' . Filesystem::validateName($name, $this->config->safe_filename) - . '.' . $format::getFileExtension() + . '.' . $format::getFileExtension(), + $this->config->encryption ); if ($file !== false) { diff --git a/src/Encrypter.php b/src/Encrypter.php new file mode 100644 index 0000000..9c25075 --- /dev/null +++ b/src/Encrypter.php @@ -0,0 +1,49 @@ +ext = '.'.$ext; + $this->folder = $keyStoragePath.'/keys'; + if(!is_dir($this->folder)){ + mkdir($this->folder, 0750, true); + } + $this->folder = $this->folder.'/'.$keyName.$this->ext; + if (!file_exists($this->folder)) { + KeyFactory::save(KeyFactory::generateEncryptionKey(), $this->folder); + chmod($this->folder, 0444); + } + $this->secretKey = KeyFactory::loadEncryptionKey($this->folder); + } + + public function encryptFile($fileInput, $fileOutput) + { + try { + return File::encrypt($fileInput, $fileOutput, $this->secretKey); + } catch (\Throwable $e) { + throw new \Exception($e->getMessage()); + } + } + + public function decryptFile($fileInput, $fileOutput) + { + try { + return File::decrypt($fileInput, $fileOutput, $this->secretKey); + } catch (\Throwable $e) { + throw new \Exception($e->getMessage()); + } + } +} \ No newline at end of file diff --git a/src/Filesystem.php b/src/Filesystem.php index 307358d..8c07cf9 100644 --- a/src/Filesystem.php +++ b/src/Filesystem.php @@ -1,5 +1,5 @@ -decryptFile($path, $tmp); + $path = $tmp; + } + } + } $file = fopen($path, 'r'); $contents = fread($file, filesize($path)); fclose($file); + if(file_exists($tmp)){ + unlink($tmp); + } + return $contents; } @@ -28,10 +46,11 @@ public static function read($path) * * @param string $path The absolute file path to write to * @param string $contents The contents of the file to write + * @param array $encryption containing encryption options * * @return boolean Returns true if write was successful, false if not. */ - public static function write($path, $contents) + public static function write($path, $contents, $encryption = null) { $fp = fopen($path, 'w+'); @@ -45,6 +64,22 @@ public static function write($path, $contents) flock($fp, LOCK_UN); fclose($fp); + if(is_array($encryption) and !empty($encryption)){ + $validate = self::validate_crypt_keys($encryption); + if($validate){ + //Check if none passed is empty + if(!empty($encryption['key_storage_path']) and !empty($encryption['key_name'])){ + $tmp = tmpfile(); + $encrypter = new Encrypter($encryption['key_storage_path'], $encryption['key_name']); + $tmp = stream_get_meta_data($tmp)['uri']; + $encrypter->encryptFile($path, $tmp); + @unlink($path); + rename($tmp, $path); + @unlink($tmp); + } + } + } + return $result !== false; } @@ -99,7 +134,7 @@ public static function validateName($name, $safe_filename) * * @return array An array, item is a file */ - public static function getAllFiles($path = '',$ext = 'json') + public static function getAllFiles($path = '', $ext = 'json') { $files = []; $_files = glob($path.'*.'.$ext); @@ -111,4 +146,12 @@ public static function getAllFiles($path = '',$ext = 'json') return $files; } + private static function validate_crypt_keys(array $sentKeys){ + $allowedKeys = array('key_storage_path', 'key_name'); + $notAllowedKeys = array_diff(array_keys($sentKeys), $allowedKeys); + if($notAllowedKeys) { + throw new \Exception("One or more keys are not allowed ".json_encode($notAllowedKeys)); + } + return true; + } } diff --git a/tests/EncryptionTest.php b/tests/EncryptionTest.php new file mode 100644 index 0000000..7b33f29 --- /dev/null +++ b/tests/EncryptionTest.php @@ -0,0 +1,16 @@ + __DIR__.'/databases', + 'encryption' => array('key_storage_path' => __DIR__.'/encrypter', 'key_name' => 'test') +]); +$db->flush(true); +$user = $db->get(uniqid()); +$user->name = 'John'; +$user->email = 'john@example.com'; +$user->save(); +$db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); +$result_from_cache = $db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); +print_r($result_from_cache); \ No newline at end of file diff --git a/tests/encrypter/keys/test.key b/tests/encrypter/keys/test.key new file mode 100644 index 0000000..bad9683 --- /dev/null +++ b/tests/encrypter/keys/test.key @@ -0,0 +1 @@ +314005005ee675e79688130b2e157beb1689f50bcdf3529948b4d4e6dbbaa434c5dc55b4aa74256c01d4bdf7a2b86a4e8f3162ffb76b454d5003e52419d15f2706c4b4c7368caa45ad4573c89111cc6fc528235773d9450ce0c626592320dd9e8adcc828 \ No newline at end of file From da5546e845ef9b6f6046d7d33245c5ae5b852b33 Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 18:52:10 +0100 Subject: [PATCH 44/51] New updated version - Encryption was added to project --- tests/EncryptionTest.php | 16 ---------------- tests/encrypter/keys/test.key | 1 - 2 files changed, 17 deletions(-) delete mode 100644 tests/EncryptionTest.php delete mode 100644 tests/encrypter/keys/test.key diff --git a/tests/EncryptionTest.php b/tests/EncryptionTest.php deleted file mode 100644 index 7b33f29..0000000 --- a/tests/EncryptionTest.php +++ /dev/null @@ -1,16 +0,0 @@ - __DIR__.'/databases', - 'encryption' => array('key_storage_path' => __DIR__.'/encrypter', 'key_name' => 'test') -]); -$db->flush(true); -$user = $db->get(uniqid()); -$user->name = 'John'; -$user->email = 'john@example.com'; -$user->save(); -$db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); -$result_from_cache = $db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); -print_r($result_from_cache); \ No newline at end of file diff --git a/tests/encrypter/keys/test.key b/tests/encrypter/keys/test.key deleted file mode 100644 index bad9683..0000000 --- a/tests/encrypter/keys/test.key +++ /dev/null @@ -1 +0,0 @@ -314005005ee675e79688130b2e157beb1689f50bcdf3529948b4d4e6dbbaa434c5dc55b4aa74256c01d4bdf7a2b86a4e8f3162ffb76b454d5003e52419d15f2706c4b4c7368caa45ad4573c89111cc6fc528235773d9450ce0c626592320dd9e8adcc828 \ No newline at end of file From 910eccb7bf288184e22ac3ef48f9ac070f117858 Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 19:13:00 +0100 Subject: [PATCH 45/51] New updated version - Encryption was added to project --- README.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 41c324c..cc04526 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [Join Discord](https://discord.gg/kywDsDnJ6C) – For support, updates and collaboration. -A Simple but Powerful Flat File Database Storage. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](README.md#2-formatting) the way you like). +A Simple but Powerful Flat File Database Storage with document encryption. No need for MySQL or an expensive SQL server, in fact, you just need your current site or application setup. All database entries are stored in files ([formatted](README.md#2-formatting) the way you like). You can even modify the raw data within the files themselves without ever needing to use the API. And even better you can put all your files in **version control** and pass them to your team without having out-of-sync SQL databases. @@ -503,6 +503,42 @@ $database->backup()->rollback(); ``` +# Changelog + +All notable changes to this project will be documented here. + +## [2.0.0] - 2023-01-25 + +### New features + + - 🌟 Added Encryption mechanism to the document. You can now encrypt and decrypt all your documents by passing an encryption array to the config settings as shown below; + +```php +require_once __DIR__."/vendor/autoload.php"; + +/** + * @settings array $encryption + * @param key_storage_path - The path to where your encryption keys are stored + * @key_name - The name of your key which points to the name of the key file (Store this name in your database) + */ + +$db = new \Filebase\Database([ + 'dir' => __DIR__.'/databases', + 'encryption' => array('key_storage_path' => __DIR__.'/encrypter', 'key_name' => 'test') +]); + +$db->flush(true); +$user = $db->get(uniqid()); +$user->name = 'John'; +$user->email = 'john@example.com'; +$user->save(); +$db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); +$result_from_cache = $db->where('name','=','John')->andWhere('email','==','john@example.com')->select('email')->results(); +print_r($result_from_cache); + +``` + +The above will encrypt your document when creating and decrypt it when fetching or quering. Please note that its required that you have the extension Sodium installed to use the encryption mechanism. ## Why Filebase? From 261eaeaf1cb2e09c860706a6d68ea08def6d0039 Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 19:14:32 +0100 Subject: [PATCH 46/51] New updated version - Encryption was added to project --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc04526..9189f5e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Doesn't that sound awesome? With Filebase, you are in complete control. Design your data structure the way you want. Use arrays and objects like you know how in PHP. Update and share your data with others and teams using version control. Just remember, upgrading your web/apache server is a lot less than your database server. -Works with **PHP 5.6** and **PHP 7+** +Works with **PHP 5.6** and **PHP 8+** ### Features From 1f6c7a94870178a062d7aff537660fd05443f2eb Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 19:19:02 +0100 Subject: [PATCH 47/51] New updated version - Encryption was added to project --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9189f5e..b658171 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Filebase is simple by design, but has enough features for the more advanced. * CRUD (method APIs) * File locking (on save) * Intuitive Method Naming +* [Encryption](README.md#11-Encryption-Added) ## Installation @@ -509,7 +510,7 @@ All notable changes to this project will be documented here. ## [2.0.0] - 2023-01-25 -### New features +## (11) Encryption Added - 🌟 Added Encryption mechanism to the document. You can now encrypt and decrypt all your documents by passing an encryption array to the config settings as shown below; From 8f90cc89f322194915a1309b3a2bd19281dcc867 Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 19:19:42 +0100 Subject: [PATCH 48/51] New updated version - Encryption was added to project --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b658171..5fe3868 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ Filebase is simple by design, but has enough features for the more advanced. * [Database Backups](README.md#10-database-backups) * [Formatting](README.md#2-formatting) (encode/decode) * [Validation](README.md#6-validation-optional) (on save) +* [Encryption](README.md#11-Encryption-Added) * CRUD (method APIs) * File locking (on save) * Intuitive Method Naming -* [Encryption](README.md#11-Encryption-Added) ## Installation From 46d7a70dc22f949b8143e8f0def17cdb8895ddc1 Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 19:21:01 +0100 Subject: [PATCH 49/51] New updated version - Encryption was added to project --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fe3868..b612686 100644 --- a/README.md +++ b/README.md @@ -508,7 +508,7 @@ $database->backup()->rollback(); All notable changes to this project will be documented here. -## [2.0.0] - 2023-01-25 +## [2.0.0] - 2023-01-25 - @mitmelon ## (11) Encryption Added From 6ea5ef62d73008bd80892698a8e3d074c4845f13 Mon Sep 17 00:00:00 2001 From: Manomite Date: Wed, 25 Jan 2023 19:32:35 +0100 Subject: [PATCH 50/51] New updated version - Encryption was added to project --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b612686..78050ca 100644 --- a/README.md +++ b/README.md @@ -508,7 +508,7 @@ $database->backup()->rollback(); All notable changes to this project will be documented here. -## [2.0.0] - 2023-01-25 - @mitmelon +## [2.0.0] - 2023-01-25 ## (11) Encryption Added @@ -578,6 +578,15 @@ Filebase will work-hard to be **backwards-compatible** when possible. Anyone can contribute to Filebase. Please do so by posting issues when you've found something that is unexpected or sending a pull request for improvements. +## All Contributors + + + + + + +
Adeyeye George
Adeyeye George
+ ## License From 510392feb7732a854b195b8711fafdf7df01a96f Mon Sep 17 00:00:00 2001 From: Adeyeye George Date: Tue, 31 Oct 2023 13:05:34 +0100 Subject: [PATCH 51/51] Fixed Bug --- src/Backup.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Backup.php b/src/Backup.php index 57ae5e9..52625ed 100644 --- a/src/Backup.php +++ b/src/Backup.php @@ -31,8 +31,9 @@ class Backup * __construct * */ - public function __construct($backupLocation = '', Database $database) + public function __construct($backupLocation, Database $database) { + $this->backupLocation = $backupLocation; $this->config = $database->getConfig(); $this->database = $database;