Download the PHP package bit-mx/data-entities without Composer
On this page you can find all versions of the php package bit-mx/data-entities. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package data-entities
Data Entities
Execute stored procedures (SQL Server, MySQL) in Laravel without all the boilerplate code.
Table of Contents
- Introduction
- Installation
- Setup
- Compatibility
- Laravel Boost
- Getting Started
- Create a Data Entity
- Creating a DataEntity class
- Connection
- Database support
- Execute the Data Entity
- Output parameters
- Mutators
- Available mutators
- Automatic mutators
- Custom mutators
- Accessors
- Available accessors
- Custom accessor
- Column aliases
- Response useful methods
- data
- Data with a key
- Data with a key and a default value
- rawData
- output
- Add data value
- Merge data
- As object
- As collection
- isEmpty / isNotEmpty
- success
- failed
- throw
- getError
- isCached
- Boot
- Events
- Middlewares
- Plugins
- AlwaysThrowOnError
- HasCache
- HasRetries
- Lazy Collection
- Data Transfer objects
- Debugging
- Testing
- Mocking the Data Entity
- Assertions
- Using factories
- Response type
- Upgrading to version 4
Introduction
Data Entities is a library that allows you to execute stored procedures easily. It is a wrapper around the Laravel's DB Facade. SQL Server and MySQL are supported out of the box, and you can register your own query executor for other database engines.
Installation
You can install the package via composer:
Setup
You need to publish the configuration file to set the connection name.
This command will create a new configuration file in the config directory.
The executers map defines which query executor is used for each database driver. See Database support.
Compatibility
This package is compatible with Laravel 11.x, 12.x, and 13.x.
It requires PHP 8.4 or above.
Laravel 11 is past security support. Prefer Laravel 12 or 13 for new apps; CI still runs Laravel 11 for compatibility.
CI runs Pest against PHP 8.4/8.5 and Laravel 11/12/13 (PHP 8.5 × Laravel 11 excluded).
MySQL integration tests live in tests/Integration and run in CI against a real MySQL service.
Locally:
Laravel Boost
If your application uses Laravel Boost, this package ships AI guidelines and an agent skill that Boost discovers automatically when you run:
No extra package dependency is required. Install Boost in your application as a dev dependency (composer require laravel/boost --dev), then run the commands above so agents pick up the data-entities guidelines and the data-entities-development skill.
Getting Started
Create a Data Entity
To create a Data Entity, you need to extend the DataEntity class and implement the resolveStoreProcedure method with the
name of the stored procedure you want to execute.
You can also override the defaultParameters method to set the default parameters for the stored procedure.
You can also use the parameters method to set the parameters for the stored procedure.
Override requiredParameters() to validate required keys before the query hits the database.
Missing keys throw MissingRequiredParameterException with a clear parameter name:
By default, the Data Entity will return a Response with a collection of records. You can change this by setting the
PHP attribute SingleItemResponse. This way, you can return a single record instead of a collection.
Creating a DataEntity class
You can use the artisan command to create a new Data Entity:
This command will create a new Data Entity in the app/DataEntities directory.
You can also generate a Data Entity from an existing stored procedure signature:
The generator introspects SQL Server (sys.parameters) or MySQL (information_schema.parameters) and fills the constructor, defaultParameters(), suggested mutators, and defaultOutputParameters().
Inventory and drift commands:
data-entities:list prints each entity with its stored procedure and connection.
data-entities:check verifies that each procedure exists and, when the entity can be constructed without arguments, compares input/output parameter names against the database signature.
Connection
You can set the connection by overriding resolveDatabaseConnection(). It may return a Laravel
connection name (string) or a live Illuminate\Database\Connection instance.
Precedence when executing:
onConnection(...) → resolveDatabaseConnection() → config('data-entities.database')
When you integrate several legacy systems, prefer one abstract base entity per system so every procedure shares the same connection (and optional defaults):
For a connection that is not defined in config/database.php, build one at runtime with
Laravel's DB::build() (Laravel 11.31+) and return or pass the Connection instance.
Credentials come from your own values (host, user, password, etc.), not from a named config entry:
Or override the connection at runtime without changing the entity class:
If the connection is already registered under a name (for example tenant_123), you can still use
DB::connection('tenant_123') or onConnection('tenant_123') as before.
Organize classes under app/DataEntities/{System}/ and point data-entities:list / data-entities:check at those paths with --path=app/DataEntities/Erp.
You can optionally set a per-entity query timeout in seconds via queryTimeout().
When set, the package applies PDO::ATTR_TIMEOUT on the connection before execution:
Transactions
When several Data Entities must succeed or fail together, wrap them in a transaction on the same connection:
Or use the helper (defaults to config('data-entities.database')). The second argument accepts a connection name or a Connection instance:
Entities that target different connections cannot share one transaction.
Database support
The package generates the correct SQL for each database engine through query executors. The executor is resolved automatically from the driver of the connection used by the Data Entity:
sqlsrv→SqlServerQueryExecutor(EXEC sp @param = :param)mysql→MySqlQueryExecutor(CALL sp(:param))
If the connection driver has no executor registered in the executers config map, an
UnsupportedQueryExecutorException is thrown.
Parameter names, stored procedure names, and output SQL types are validated before the query is
compiled. Names must be identifiers (post_id, dbo.spListPost); SQL types must look like
INT, NVARCHAR(100), or DECIMAL(10,2). Invalid values throw InvalidIdentifierException
to prevent SQL injection through interpolated identifiers.
You can force a specific executor for a single Data Entity by overriding the resolveQueryExecutor method:
To support another database engine, create a class that implements
BitMx\DataEntities\Executers\Contracts\QueryExecutorContract (or extends
BitMx\DataEntities\Executers\AbstractQueryExecutor) and register it in the config:
Execute the Data Entity
To execute the Data Entity, you need to call the execute method on the Data Entity instance.
The execute method returns a Response object that contains the data returned by the stored procedure.
Output parameters
Stored procedure output parameters are supported via defaultOutputParameters(). Map each output parameter name to its SQL type.
- On SQL Server, the package will
DECLAREthe variables, pass them asOUTPUT, and select them back into$response->output(). - On MySQL, the package passes them as session variables (
CALL sp(:param, @out)) and then reads them with a separateSELECT @out AS outafter the call. The declared SQL type is ignored because MySQL does not require aDECLAREstatement.
You can also add output parameters at runtime with $dataEntity->outputParameters()->add('name', 'INT').
Use $response->rawOutput() when you need the values before accessors/aliases are applied.
Mutators
You can use the mutators method to transform the parameters before sending them to the stored procedure.
This will transform the date parameter to a formatted date string before sending it to the stored procedure.
Available mutators
-
datetime: Converts the value to a datetime string using the specified format. You can pass a format as an argument to the cast. Examples:
datetimeReturnsY-m-d H:i:sdatetime:Y-m-ddatetime:H:i:sdatetime:Y-m-d H:i:s
- date:
Converts the value to a date
Y-m-d - bool:
Converts the value to a boolean as int.
Example: If the value is
true, it will be converted to1, and if it isfalse, it will be converted to0. - int: Converts the value to an integer.
-
float / decimal: Converts the value to a float. You can pass the number of decimals as an argument to the cast. Example:
floatReturns a float rounded to 2 decimals.float:4Returns a float rounded to 4 decimals.float:0Returns a float rounded to 0 decimals.decimalis an alias offloat.
- string: Converts the value to a string.
-
json: Converts the value to a JSON string. Example:
- If you pass an array, it will be converted to a JSON string.
[1, 2, 4]will be converted to"[1,2,4]".['name' => 'John']will be converted to'{"name":"John"}'.- You can pass the JSON options as an argument to the cast.
'json:'. JSON_PRETTY_PRINTwill return the JSON string with theJSON_PRETTY_PRINToption.
- BackedEnum class-string: You can also map a parameter to a backed enum class. The mutator will use the enum's value.
Automatic mutators
When no mutator is defined for a parameter, the package still transforms some types automatically:
bool→0/1BackedEnum→ enum valueDateTimeInterface→Y-m-d H:i:snulland other scalars are passed through
Custom mutators
You can create custom mutators by implementing the Mutable interface.
You can create a new mutator using the artisan command.
Accessors
You can use the accessors method to transform the data returned by the stored procedure.
This will transform the contact_id key to an integer before returning the data.
Available accessors
- datetime / date:
Converts the value to a
DateTimeinstance. - datetime_immutable / date_immutable:
Converts the value to a
DateTimeImmutableinstance. - bool / boolean:
Converts the value to a boolean.
Example: If the value is
1, it will be converted totrue. - int / integer: Converts the value to an integer.
- float / decimal: Converts the value to a float.
- string: Converts the value to a string.
- array: Converts the value from a JSON string to an array.
- object: Converts the value from a JSON string to an object.
- collection: Converts the value from a JSON string to a Laravel Collection.
- BackedEnum class-string:
You can map a column to a backed enum class (
Enum::tryFrom($value)).
Custom accessor
You can create custom accessors by implementing the Accessable interface.
You can create a new accessor using the artisan command.
Column aliases
You can rename response columns (and output parameter keys) using the alias method.
Aliases are applied before accessors.
You can also set aliases at runtime with $dataEntity->setAlias([...]).
Response useful methods
The Response object has some useful methods to work with the data returned by the stored procedure.
data
The data method returns the data returned by the stored procedure as an array (after aliases and accessors).
Data with a key
You can get the data with a key:
Data with a key and a default value
You can get the data with a key and a default value:
rawData
Returns the data before aliases and accessors are applied:
output
Returns stored procedure output parameter values:
Add data value
You can add a value to the data array:
You can also pass an array:
Merge data
You can merge an array with the data array:
As object
You can get the data as an object:
As collection
You can get the data as a collection:
isEmpty / isNotEmpty
success
The success method returns true if the stored procedure was executed successfully, and false otherwise.
failed
The failed method returns true if the stored procedure failed, and false otherwise.
Database failures (QueryException and PDOException) are captured into the Response as a soft failure
(success() is false). Programming errors such as invalid mutators or unsupported executors still throw.
throw
By default, the Response object won't throw an exception if the stored procedure fails. You can throw an exception
manually using the throw method.
getError
Returns the error message when the response failed:
isCached
Returns whether the response was served from cache (when using the HasCache plugin):
Boot
You can use the boot method to execute code before the stored procedure is executed.
Traits
You can use traits to add functionality to your Data Entities. Add a boot{TraitName} method so it runs during boot.
The bootTaggable method will be called before the stored procedure is executed.
Events
Real database executions dispatch Laravel events you can listen to for logging or APM:
BitMx\DataEntities\Events\DataEntityExecuted— successful executionBitMx\DataEntities\Events\DataEntityFailed— soft failure (QueryException/PDOException)
Both events expose the Data Entity, pending query, response, compiled SQL, and duration in milliseconds. Failed events also expose the captured exception.
Fake / mocked executions do not dispatch these events.
Middlewares
You can use middlewares to execute code before and after the stored procedure is executed.
You can also use an invokable class as a middleware. This class should implement the QueryMiddleware or
ResponseMiddleware interface.
Plugins
You can use plugins to add functionality to your Data Entities.
AlwaysThrowOnError
The AlwaysThrowOnError plugin will throw an exception if the stored procedure fails.
HasCache
The HasCache plugin will cache the data returned by the stored procedure.
The Data Entity should implement the Cacheable interface.
Optional hooks:
cacheKey(PendingQuery $pendingQuery): ?string— custom cache key (default is a SHA-256 hash of the class, stored procedure, connection, parameters, and output parameters)cacheDriver(): string— cache store name (default:config('cache.default'))
The default cache key includes the database connection name, so the same entity executed against different connections does not share cache entries.
Cached responses store raw data and re-apply accessors when the response is restored, so non-idempotent accessors are not applied twice.
Cache payloads are unserialized with an allow-list of package classes only. If cacheExpiresAt() is in the past, the TTL is floored to 1 second.
You can invalidate the cache for the next execution using invalidateCache() on the Data Entity instance:
Or you can disable caching temporarily using disableCaching():
You can also clear an existing cache entry with clearCache():
The Response object has an isCached method to check if the data was served from cache:
HasRetries
The HasRetries plugin retries transient database failures such as deadlocks and timeouts.
Lazy Collection
Use the #[UseLazyQuery] attribute when the stored procedure can return a large (or unbounded) result set and you want to consume rows through a Laravel LazyCollection instead of loading everything via data() / collect() up front.
With #[UseLazyQuery], the executor runs the procedure through a database cursor. Rows are not fully materialised until you iterate lazy() or stream() on the response.
lazy() and stream() both return a Laravel LazyCollection over the same cursor. The difference is memory and re-iteration: lazy() remembers rows after the first pass so you can iterate again — on large datasets that means memory grows to the full result set size. Prefer stream() for large sets. If you hit Lazy stream has already been consumed, switch to lazy() when you need multiple passes on a moderate set, or call execute() again for a fresh cursor.
lazy() — re-iterable (remembers rows)
Default: lazy() / lazy(remember: true). After the first pass, rows are kept in memory (LazyCollection::remember()), so you can iterate or transform the collection more than once without re-running the stored procedure.
stream() — single-pass (low memory)
Use stream() (or lazy(remember: false), which is an alias) when you must avoid accumulating the full result set. Process one row at a time; a second iteration throws a RuntimeException.
Risks of lazy() on large datasets
The name “lazy” does not mean permanently low memory. After the first iteration, lazy() remembers every row already seen. Memory can grow to the size of the entire result set — similar to calling collect() once you have walked the cursor.
Operations that force a full traversal (count(), all(), toArray(), multiple foreach loops, or pipelines that reuse the same collection) trigger that accumulation.
| Prefer | When |
|---|---|
stream() |
Massive exports, ETL, millions of rows, or any flow that only needs one pass |
lazy() |
Moderate result sets where you will traverse or transform more than once and want to avoid re-executing the SP |
Even with stream(), MySQL may still buffer the whole result set unless the connection is configured for unbuffered queries (see below).
If stream() was already consumed
A second iteration over the same stream raises:
RuntimeException: Lazy stream has already been consumed and cannot be re-iterated. Use lazy() for a re-iterable collection.
What to do:
- You need multiple passes on the same response — use
$response->lazy()from the start (rows are remembered after the first pass; watch memory on large sets). - You already consumed
stream()and need the data again — callexecute()again and obtain a newstream()/lazy(). The current response’s stream cannot be reset. lazy(remember: false)— same single-pass limitation asstream().
Restrictions
When using #[UseLazyQuery], the response type only supports a collection. Combining it with #[SingleItemResponse] throws an exception.
#[UseLazyQuery] is also incompatible with output parameters. Lazy queries use a cursor over a single result set, so output values would be lost; combining both throws InvalidLazyQueryException.
MySQL and true streaming
On MySQL, PDO buffers result sets by default. For true streaming, configure the connection with unbuffered queries:
Data Transfer objects
Map stored-procedure rows into PHP objects and read them with $response->dto().
#[MapTo] — automatic mapping
#[MapTo] is an optional shortcut: the package reflects the DTO constructor and fills each parameter from the matching key in the response row (after aliases and accessors). Calling $response->dto() runs that mapping.
DTO rules:
- Prefer a constructor-based class; parameter names must match the row keys (
id,title, …). - Missing keys use the parameter’s default value when available, otherwise
null.
Single item
Combine #[SingleItemResponse] with #[MapTo(Dto::class)]:
Collection of DTOs
Pass Laravel’s Illuminate\Support\Collection (or a compatible subclass) as the second argument. Each row becomes a DTO and the result is wrapped in that collection class:
Empty result sets yield an empty collection. A single-item response with a collection class yields a collection of one DTO.
Any class constructible as new $collectionClass($items) works (for example Illuminate\Database\Eloquent\Collection).
Manual createDtoFromResponse()
For nested objects, Spatie Data, custom transforms, or anything beyond constructor key matching, override createDtoFromResponse(). A manual override always wins over #[MapTo].
Debugging
You can call dd and ddRaw methods to debug the query sent to the database.
Testing
You can create integration tests for your Data Entities easily.
Mocking the Data Entity
You can mock the Data Entity using the DataEntity::fake method. Assertions and helpers live on DataEntity itself (facade-style), so you do not need to capture a mock client.
Reset mocks between tests (recommended in tests/Pest.php):
When using the fake method, the execute method will return the data specified in the MockResponse::make method and
won't execute the stored procedure.
Fluent mock responses
Assertions
You can use assertions to verify that the Data Entity was executed.
Available assertions:
- assertExecuted: Assert that the Data Entity was executed.
- assertNotExecuted: Assert that the Data Entity was not executed.
- assertNothingExecuted: Assert that no Data Entity was executed.
- assertExecutedCount: Assert that the Data Entity was executed a specific number of times.
- assertExecutedOnce: Assert that the Data Entity was executed once.
- assertTotalExecutedCount: Assert the total number of Data Entity executions.
- assertExecutedInOrder: Assert Data Entities were executed in a specific order.
- assertExecutedWith: Assert that the Data Entity was executed with matching parameters (array subset, parameter closure, or
RecordedExecutionclosure).
You can also fake with a closure, a sequence, merge more mocks, or set a fallback:
Using factories
You can use factories to create fake data for your Data Entities.
To create a factory you should extend the DataEntityFactory class and implement the definition method.
You can use the faker property to generate fake data.
Pass the factory (or its created data) to MockResponse::make inside DataEntity::fake():
You can also pass an array created with the create method:
You can also use the count method to create an array of fake data:
You can use the state method to change the default values of the factory:
Or create a new method in the factory to change the default values:
You can create a fake with an exception:
Response type
You can set the factory response type using the responseType method.
You can also change the response type on the factory instance:
You can create a new factory using the artisan command.
This command will create a new factory in the tests/DataEntityFactories directory.
Upgrading to version 4
Key Changes
Version 4.0 introduces two primary breaking changes to simplify the DataEntity class.
1. Removal of the responseType Property
The $responseType property has been removed from the DataEntity class. By default, all responses now return a collection of items.
To specify that a response should return a single item, you must now use the \BitMx\DataEntities\Attributes\SingleItemResponse attribute directly on your DataEntity class.
Example:
2. Removal of the $method Property
The $method property has also been removed from the base DataEntity class, as it is no longer utilized by the package.
Automated Upgrade with Rector
To facilitate a smooth transition, we provide a set of Rector rules that can automate the upgrade process for your project.
Follow these steps to update your code automatically.
Step 1: Install Rector
First, ensure you have Rector installed as a development dependency in your project.
Step 2: Configure Rector
Next, create or update your rector.php configuration file in the root of your project to include the custom rules for this package.
Step 3: Run the Upgrade
Finally, execute the Rector process command, pointing it to the directory where your DataEntity classes are located.
Rector will analyze the files and apply the necessary modifications to align them with the new standards of version 4.0.
All versions of data-entities with dependencies
ext-pdo Version *
illuminate/support Version ^11.0|^12.0|^13.0
illuminate/database Version ^11.0|^12.0|^13.0
fakerphp/faker Version ^1.0