This package provides the base functions and types for the database specific packages.
The main part of this package functions are helpers to work with the Identifier instances.
Idable queries are a set of packages that are at the core a multi-database wrapper.
While you can use it as a wrapper with the same functions and types per database, the libraries provide an abstraction for the database names and parameters.
At the base of the abstraction is the Identifier interface. It is nothing more than a library specific name for enums.
enum Users implements Indentifier
{
case Users; // It is recommended to use enun name for the table/collection/set/... to make the identifier more universal
case Name;
}
A backed enum is recommended to separate database name from the enum name.
A SQL query, SELECT name FROM users WHERE name = 'me';, can now be written as SELECT ~Users:Name FROM ~Users:Users WHERE ~Users:Name = :Users:Name;.
A Redis query like HMSET users name "Hello" email "World" can be written as HMSET ~Users:Users ~Users:Name :Users:Name ~Users:Email :Users:Email.
And so on with other database types.
note: The placeholders are case-insensitive, but for the best compilation path in PHP it is recommended to use capitals.
To make it easier to add multiple parameters an CustomParameterIdentifier attribute can be added to an Identifier instance.
This signals to the parameter functions that the parameter value will use a transformer to replace a single placeholder.
#[CustomParameterIdentfier('Xwero\IdableQueriesRedis\setParameterTransformer')]
enum Set implements Identfier
{
case Users;
}
Now the Redis query can be written as HMSET ~Users:Users :Set:Users.
And depending on the values in the IdableParameterCollection instance the query will be changed.
Each database package will have predefined transformer functions. Creating the Identifier instance is up to the implementers.
The libraries will have map functions that transform the result of the query in an array-like structure where the key is an Identifier instance.
As an example the SELECT ~Users:Name FROM ~Users:Users WHERE ~Users:Name = :Users:Name; query result called with the createMapFromFirstLevelResults function will have the $map[Users:Name] value me.
This prevents typos when using the results.
The libraries are build with utility in mind. That is why the main functionality is in the functions, rather than in objects. Use as much or as little as you like.
This is the more dangerous version of the collectIdableParameters function, as it adds the values to the query without preparation.
addIdableParameters('SELECT * FROM ~Users:Users WHERE ~Users:Name = :Users:Name;', new IdableParameterCollection(User::Name, 'me'')) results in SELECT * FROM ~Users:Users WHERE ~Users:Name = me
Used by the database system packages.
Helper function to create a Map instance from an associate array. The benefit of a Map instance is that the keys are identifiers.
Used by createMapFromFirstLevelResults and createMapFromSecondLevelResults.
This function allows the application code to prepare the parameters before adding it to the query.
Used by replaceParametersInQuery.
Function with extra checks on top of buildLevelMap.
note: This is more robust function, and should be the one used in a function chain.
Used by the database system packages.
When the query returns multiple items use this function to create a MapCollection.
Used by the database system packages.
This function accepts the class and case as a string and insures the return is either null or an identifier.
It is possible to add a number to the case in the occasion the same identifier needs to be used more than once.
As an example WHERE ~Users:Name = :Users:Name1 AND ~Users:Name != :Users:Name2
Used by queryToPlaceholderIdentifierCollection.
This function gets the default regex or a custom one from the IDENTIFIER_REGEX environment variable.
This function get the default regex or a custom one from the PARAMETER_REGEX environment variable.
note: Both regexes should have a colon as divider between the class and the case.
Gets a backed enum value or a lower string basic enum name.
Used by buildlevelmap and PlaceholderReplacementCollection.
This function extracts the strings that match the identifier regex and makes identifiers from the strings.
An error is returned when placeholders are found but the collections is empty. the most likely cause is a wrong namespace. It is not possible to return an error when only one or a few namespaces are wrong. To prevent unexpected results it is best to use the namespaces argument when the functions provide it.
note: The collection is sorted from largest string size to smallest string size of the placeholders. This is to prevent bad replacements.
Used by addQueryParameters, collectQueryParameters, createMapFromFirstLevelResults, createMapFromSecondLevelResults and replaceIdentifiersInQuery.
Replaces the identifier placeholders from the query with the database names.
Used by the database packages.
Replaces the parameter placeholders where the data isn't matched by query placeholder.
:Arr:Test will become (:Arr:Test_0,:Arr:Test_1) when used in the PDO package.
The number of placeholders is based on the data in the IdableParameterCollection.
A $placeholderTransformer closure can be added to make sure the placeholders don't contain characters the database doesn't recognize.
Used by the database packages.
When using a PHP version under 8.5, this function can be used to have a similar experience than with the pipe operator.
$query = 'SELECT ~Users:Name, ~Users:Email FROM ~Users:Users WHERE ~Users:Id = :UsersId';
$namespaces = new BaseNamespaceCollection('Test\Identifiers');
$result = replaceIdentifiersInQuery($query, $namespaces)
|> fn($query) => replaceParametersInQuery($query, new IdableParameterCollection(Users::Id, 1), $namespaces)
|> fn($queryAndParameters) => someDatabaseFunction($queryAndParameters)
|> fn($data) => createMapFromSecondLevelResults($data, $query, namespaces: $namespaces)
;
// with runChain
$query = 'SELECT ~Users:Name, ~Users:Email FROM ~Users:Users WHERE ~Users:Id = :UsersId';
$namespaces = new BaseNamespaceCollection('Test\Identifiers');
$result = runChain(new Chain(
fn() => replaceIdentifiersInQuery($query, $namespaces)
fn($query) => replaceParametersInQuery($query, new IdableParameterCollection(Users::Id, 1), $namespaces),
fn($queryAndParameters) => someDatabaseFunction($queryAndParameters),
fn($data) => createMapFromSecondLevelResults($data, $query, namespaces: $namespaces)
));
Most of the collection types are added to make sure the content is of a certain type.
It is used to match aliases in the query return with identifiers.
The constructor only accepts Identifier and string instances.
It has the method:
- getIdentifier: finds the matching
Identifierinstance by a string value.
It extends TypeCollection.
Has a single array to contain the collection items. Can be used for collections with a single type.
It has the methods:
- getAll: returns array
- isEmpty: checks the array size
It is used to make the identifier placeholders in the queries shorter.
The constructor only accepts string values.
Extends BaseCollection.
Used to add closures to the runChain function.
The constructor only accepts Closure values.
Extends BaseCollection.
This is an attribute that is added to Identifier objects to signal to the parameter functions a single placeholder
should be replaced with placeholders that match a data structure used by a data transformer.
The catch-all exception type to make it easier to let them pass through a function chain.
To allow query placeholders with a trailing number this class is created get the value by Identifier and number.7
An example is new IdableParameter(Users::Name, 'me', 1).
Used to add values to the parameter identifier placeholders in the query.
:Users:name is replaced by me when executing the query with the collection intance, new IdableParameterCollection(Users::Name, 'me').
The constructor accepts IdentifierInterface, int, array, float and string instances.
It has the methods:
- add: adds an
IdableParameterinstance to the collection - findValueByIdentifierAndPlaceholder: used by the
addIdableParametersandcollectIdableParametersfunctions
Extends BaseCollection.
The interface all the enums must implement to be used as placeholders in the queries and keys in maps.
A backed enum is recommended because it provides the best configuration. When it is a basic enum the case name will be lowercased to replace the placeholders.
A convenience class were the message needs to added to create an Error instance with and instance of the JSONException as the exception.
The message you add to the exception is appended with the JSON error message from PHP.
Added to make the language more consistent.
The constructor only allows Map instances.
It has the method:
- add: appends a
Mapinstance to the collection.
Extends BaseCollection.
The database packages have their implementation of this class for the functions to differentiate between the idable parameter and native parameter functionality.
This class binds the placeholder with the identifier, and optionally the value.
The class required properties are placeholder and identifier.
The value property is used for collecting the data that a function passes on.
The prefix and suffix properties are used to manipulate the placeholder return.
It has the methods:
- getFullPlaceholder: which concatenates the
prefix,placeholderandsuffixproperty values. - getCustomValue: when the ´identifier´ value has a
CustomParameterIdentifierattribute, this method will execute the data transformer function
The constructor only accepts PlaceHolderIdentifier instances.
It has the methods:
- add: appends a
PlaceHolderIdentifieritem to the collection. - getPlaceholderReplacements: returns a flattened array in case the placeholders in the query need to be replaced.
- getPlaceholdersAsText: calls the
getFullPlaceholderon every item of the collection to create a string. - getPlaceholderValuePairs: returns a flattened array with the placeholders and matching values
Extends BaseCollection.
The base collection to be used when one type is used for the keys.
In this library the key for most collections is an Identifier instance.
- Use the namespaces argument of the functions to prevent unexpected results because of typos or changed namespaces.