Repository navigation
API: Nether\Datastore
In addition to the following API, the Datastore class implements the following SPL interfaces:
ArrayAccessCountableIterator
The primary way to initialise a datastore object is to give it an iterable thing of things.
$Data = new Datastore([ ... ]);
$Data = Datastore::New([ ... ]);
There are additional factory methods for more specific cases.
// from a file on disk
$Data = Datastore::FromFile('cache/posts.json');
// from an exploded string
$Data = Datastore::FromString('asdf');
// from a delimited string
$Data = Datastore::FromString('a|s|d|f', '|');
// from a merged set of lists
$Data = Datastore::FromStackMerge($List1, $List2, $List3);
// from a blended set of lists
$Data = Datastore::FromStackBlend($List1, $List2, $List3);
There are two events fired during construction, one before and one after the supplied data is stored within itself. Classes can extend the datastore, and override these methods to preconfigure any needs.
Called before the data is Imported. This would be a good place to define any import filters needed.
Called after the data is imported. This could used to post process the imported data to fit whatever needs.
Import the supplied data to use. Any defined Import Filters will be applied to the data as it is imported.
$Data->Import([ 'One'=> 1, 'Two'=> 2, 'Three'=> 3 ]);
Import data from the sepcified file on disk. Any defined Import Filters will be applied to the data as it is loaded.
$Data->Load('cache/posts.json');
If the file ends with
.jsonit is expected to be a valid JSON object. Otherwise it is expected to be valid PHSON (from PHP's built-in serialize()).
Export the current working dataset as an array.
$Raw = $Data->Export();
Export the current working dataset to the specified file on disk.
$Data->Write('cache/posts.json');
If the file ends with
.jsonit will write a JSON format file. Otherwise it will write PHSON format (from PHP's built-in serialize()).
There are two types of filters that can be used: Value (runs when a value is fetched) and Import (runs when a value is stored). There are no filters by default.
-
Value filters can be defined at any time as they do not alter the stored data, rather executed each time the value is read out.
-
Import Filters should be defined before the datastore is populated. Values already stored within will not be filtered until the next time they are updated.
Set a Value Filter for a specific key. Can take either a callable function or a list of them to run in series. Data will be run through the filters each time they are read.
// make sure we always get an integer back.
$Data->Set('ID', $_GET['id']);
$Data->SetValueFilter('ID', fn(mixed $V)=> (int)$V);
var_dump($Data->Get('ID'));
$Func: fn(mixed $Value): mixed
Unset Value Filters for a specific key.
// make sure we always get an integer back.
$Data->UnsetValueFilter('ID');
Set Import Filters for a specific key. Can take either a callable function or a list of them to run in series. Data will be run through the defined filters when they are added or updated.
// make sure we only ever store an integer here.
$Data->SetImportFilter('ID', fn(mixed $V)=> (int)$V);
$Data->Set('ID', $_GET['id']);
var_dump($Data->Get('ID'));
$Func: fn(mixed $Value): mixed
Unset Import Filters for a specific key.
$Data->UnsetImportFilter('ID');
The protection API is an aid to guard values from being dumped by debugging
tools like var_dump() and print_r(). The data is not altered in any way,
only masked when printed by anything using PHP's magic __debugInfo system.
Use case: about to var_dump() something you probably shouldn't, like a
configuration, but nothing can stop it because you are an agent of chaos.
Someone smarter than you can use this to flag things like misc API keys when
they define them, to try and avoid you shooting yourself later.
Add a key to protect from debugging info.
$Data->SetProtectedKey('APIKEY');
var_dump($Data);
If
$Stripis FALSE it will print "[protected thing]" in place of the value.
If
$Stripis TRUE it will completely omit the key as if it does not exist.
Remove a key from debugging protection.
$Data->UnsetProtectedKey('APIKEY');
var_dump($Data);
Set and or overwrite the specified key to the specified value. Value will be transformed by any Import Filters that were defined for that key before stored.
$Data->Set('ID', 42);
Same as Set() except if the key already exists, it will NOT be overwritten.
Useful for setting default config values late if some user config has already
been supplied.
$Data->Define('ID', 69);
Removes the key and value from the datastore.
$Data->Unset('ID');
Return how many items are stored.
$Num = $Data->Count();
Check if a key exists. Does not care what the value of that key is, only that we have one.
if($Data->Has('ID'))
printf('dataset contains an ID.%s', PHP_EOL);
Fetch a specific value. Value will be transformed by any Value Filters that were defined before it hands it back to you.
printf('ID: %d.%s', $Data->Get('ID'), PHP_EOL);
Fetch a list of values. Values will be transformed by any Value Filters that were defined before it hands them back to you.
$List = $Data->Pick('One', 'Two', 'Three');
printf('picked %d things.%s', $List->Count(), PHP_EOL);
Append an item to either end of the dataset.
$Users->Push($Who);
Pop off an item from either end of the dataset.
$Who = $Users->Pop();
Sort an array with the specified callable. If no callable provided then uses the default PHP ksort() and asort() functions.
$Users->Sort(fn(User $A, User $B)=> $A->Username <=> $B->Username);
$Func: fn(mixed $Value) => void
$Func: fn(mixed $Key, mixed $Value) => void
Run a callable for each item in the dataset.
// debug dump of users.
$Users->Each(fn(User $Who)=> var_dump($Who));
$Func: fn(mixed $Value) => mixed
$Func: fn(mixed $Key, mixed $Value) => mixed
Map the dataset to a new Datastore object using the specified callable.
// make a list of email addresses.
$Emails = $Users->Map(fn(Users $Who)=> $Who->Email));
$Func: fn(mixed $Value) => mixed
$Func: fn(mixed $Key, mixed $Value) => mixed
Map this dataset in place using the specified callable.
// just keep a list of email addresses.
$Users->Remap(fn(Users $Who)=> $Who->Email));
$Func: fn(mixed $Value) => bool
$Func: fn(mixed $Key, mixed $Value) => bool
Distill the dataset into a new Datastore object using the specified callable filter function. Returning TRUE from the callable keeps the item, returning FALSE discards it.
// get a list of only users who opt in.
$OptedIn = $Users->Distill(fn(User $Who)=> $Who->HasOptedIn('email'));
$Func: fn(mixed $Value) => bool
$Func: fn(mixed $Key, mixed $Value) => bool
Filter the dataset in place using the specified callable filter function Returning TRUE from the callable keeps the item, returning FALSE discards it.
// keep only users who opt in
$Users->Filter(fn(User $Who)=> $Who->HasOptedIn('email'));
$Func: fn(mixed $Key, mixed $Value) => bool
Reindex this dataset. The simple version will turn it into a simple numerically sequenced list. The complex version has a few different behaviours depending on the return supplied callable.
* NULL
Nothing happens. Key and value remain unchanged.
* bool FALSE
Key and data is removed from the dataset completely.
* string <key>
Data is moved to the new key name.
* array [ <key>, <value> ]
Data is moved to the new key name, and the value overwritten with the
supplied value.
// listify dataset after filtering left indexing gaps.
$Data->Reindex();
// snake_case to PascalCase the dataset key names.
$Data->ReindexKeyValue(
fn(string $Key, mixed $Val)
=> str_replace(' ', '', ucwords(str_replace('_', ' ', $Key)))
);
$Func: fn(mixed $Value, mixed $Prev) => bool
$Func: fn(mixed $Key, mixed $Value, mixed $Prev) => bool
Perform a rollup operation (accumulation / reduce) by walking across all items carrying a value that they can alter with the supplied callable.
// calculate total points in current economy.
$Total = $Users->Roll(fn(User $Who, int $Prev)=> $Prev + $Who->Points);
Join each item together into a giant string using the specified delimiter.
// get a pipe delimited list of things.
$Row = $Data->Join('|');
Randmise the order of this dataset.
$Data->Shuffle();
Fetch a list of all the keys for this dataset.
$Keys = $Data->GetKeys();
Fetch a list of all the values in this dataset.
$Vals = $Data->GetValues();
Get the first key of this dataset.
$First = $Data->GetFirstKey();
Get the last key of this dataset.
$Last = $Data->GetLastKey();
Get the first value in this dataset.
$First = $Data->GetFirstValue();
Get the last value in this dataset.
$Last = $Data->GetLastValue();
Test if the dataset is empty.
if($Data->IsEmpty())
echo 'Dataset is empty.', PHP_EOL;
Test if specified key is the first key in this dataset.
foreach($Data as $Key => $Val) {
if($Data->IsFirstKey($Key))
echo '<ul>';
// ...
}
Test if specified key is the last key in this dataset.
foreach($Data as $Key => $Val) {
// ...
if($Data->IsLastKey($Key))
echo '</ul>';
}
Test if the specified item is boolean TRUE.
if($Config->IsTrue('something'))
PerformFeatureSomething();
Test if the specified value is boolean TRUE, or something that evaluates to true. This test differs from PHP's default handlng of what is trueish.
TRUE, 1, '1', 'T', 'TRUE', 'Y', 'YES' [case-insensitive]
if($Config->IsTrueEnough('something'))
PerformFeatureSomething();
Test if the specified item is boolean FALSE.
if($Config->IsFalse('something')) {
echo 'skipping feature: Something', PHP_EOL;
return;
}
Test if the specified value is boolean FALSE, or something that evaluates to false. This test differs from PHP's default handlng of what is falsy.
NULL, FALSE, 0, '0', 'F', 'FALSE', 'N', 'NO' [case-insensitive]
if($Config->IsFalseEnough('something')) {
echo 'skipping feature: Something', PHP_EOL;
return;
}
(also anything not coverved by IsTrueEnough, example: 'asdf')
Test if the specified item is literal NULL and/or undefined.
if($Config->IsNull('something')) {
echo 'missing configuration for something', PHP_EOL;
return;
}
Test if the specified value is literal NULL, or something that evaluates to NULL. This test differs from PHP's default handlng of what is nullish.
NULL, '', 'NULL' [case-insensitive]
if($Config->IsNullEnough('something')) {
echo 'missing configuration for something', PHP_EOL;
return;
}