Framework-agnostic PHP library with deep framework integration β get the power of framework-specific solutions without the lock-in.
Transform complex data structures, create type-safe DTOs and simplify data operations with expressive syntax. Works standalone in Pure PHP or with deep integration for Laravel and Symfony. Includes DataMapper, SimpleDto/LiteDto, DataAccessor/Mutator/Filter and utility helpers (MathHelper, EnvHelper, etc.).
// From this messy API response...
$apiResponse = [
'data' => [
'departments' => [
['users' => [['email' => 'alice@example.com'], ['email' => 'bob@example.com']]],
['users' => [['email' => 'charlie@example.com']]],
],
],
];
// ...to this clean result in a few lines
$accessor = new DataAccessor($apiResponse);
$emails = $accessor->get('data.departments.*.users.*.email');
// ['alice@example.com', 'bob@example.com', 'charlie@example.com']π― Framework-Agnostic + Deep Integration β’ Pure PHP with zero dependencies β’ Optional Laravel & Symfony integration β’ No framework lock-in
π Full Documentation β’ Getting Started β’ API Reference
π Support the Development - Help us build better tools for the PHP community
// β Without Data Helpers
$emails = [];
foreach ($data['departments'] ?? [] as $dept) {
foreach ($dept['users'] ?? [] as $user) {
if (isset($user['email'])) {
$emails[] = $user['email'];
}
}
}
// β
With Data Helpers
$emails = $accessor->get('departments.*.users.*.email');- π― Framework-Agnostic + Deep Integration - Pure PHP with zero dependencies, optional deep Laravel/Symfony integration
- Type-Safe - PHPStan Level 9 compliant with 4700+ tests
- Fast - SimpleDto with #[UltraFast] is up to 12.5x faster than Other Serializer
- Zero Dependencies - No required dependencies, optional framework integrations
- No Framework Lock-In - Use framework features without being tied to a framework
- No-Code Mapping - Store templates in database, create with drag-and-drop editors
composer require event4u/data-helpersRequirements: PHP 8.2+
Framework support (all optional):
- π΄ Laravel 9+ - Collections, Eloquent Models
- β« Symfony/Doctrine 6+ - Collections, Entities
- π§ Standalone PHP - Works out of the box
π Installation Guide β’ Configuration
The best of both worlds: Use Data Helpers as a standalone library in pure PHP, or leverage deep framework integration for Laravel and Symfony β without framework lock-in.
Zero dependencies required. Works out of the box with:
- β Pure PHP - Arrays, objects, JSON, XML
- β Any Framework - No framework-specific code required
- β Portable - Move between frameworks without code changes
// Works everywhere - no framework needed
$dto = UserDto::fromArray(['name' => 'John', 'email' => 'john@example.com']);
$json = json_encode($dto);When you need it: Add framework-specific features without changing your core code.
// 1. Controller Injection - Automatic validation & filling
class UserController extends Controller
{
public function store(UserDto $dto): JsonResponse
{
// $dto is automatically validated and filled from request
$user = User::create($dto->toArray());
return response()->json($user, 201);
}
}
// 2. Eloquent Model Integration
$user = User::find(1);
$dto = UserDto::fromModel($user); // From Model
$dto->toModel($user); // To Model
// 3. Laravel-Specific Attributes
class UserProfileDto extends SimpleDto
{
public function __construct(
public readonly string $name,
#[WhenAuth] // Only when authenticated
public readonly ?string $email = null,
#[WhenCan('edit-posts')] // Only with permission
public readonly ?string $editUrl = null,
#[WhenRole('admin')] // Only for admins
public readonly ?array $adminPanel = null,
) {}
}
// 4. Artisan Commands
php artisan make:dto UserDto
php artisan dto:typescript
php artisan dto:migrate-spatie// 1. Controller Injection - Automatic validation & filling
class UserController extends AbstractController
{
#[Route('/users', methods: ['POST'])]
public function create(UserDto $dto): JsonResponse
{
// $dto is automatically validated and filled from request
$user = new User();
$dto->toEntity($user);
$this->entityManager->persist($user);
$this->entityManager->flush();
return $this->json($user, 201);
}
}
// 2. Doctrine Entity Integration
$user = $this->entityManager->find(User::class, 1);
$dto = UserDto::fromEntity($user); // From Entity
$dto->toEntity($user); // To Entity
// 3. Symfony-Specific Attributes
class UserProfileDto extends SimpleDto
{
public function __construct(
public readonly string $name,
#[WhenGranted('ROLE_ADMIN')] // Only with permission
public readonly ?string $email = null,
#[WhenSymfonyRole('ROLE_MODERATOR')] // Only for moderators
public readonly ?array $moderationPanel = null,
) {}
}
// 4. Console Commands
php bin/console make:dto UserDto
php bin/console dto:typescript| Feature | Pure PHP | Laravel | Symfony |
|---|---|---|---|
| DTOs & Validation | β | β | β |
| Controller Injection | β | β Auto | β Auto |
| Request Validation | β Manual | β Auto | β Auto |
| Model/Entity Mapping | β Plain Objects | β Eloquent | β Doctrine |
| Framework Attributes | β | β Auth/Can/Role | β Granted/Role |
| Code Generation | β | β Artisan | β Console |
| TypeScript Export | β | β | β |
The Power: Get framework-specific features when you need them, without framework dependencies in your core code.
π Laravel Integration Guide β’ Symfony Integration Guide
The heart of this library: Data mapping and DTOs for transforming and structuring data, plus powerful data manipulation tools.
Access deeply nested data with dot notation, wildcards, and powerful transformation methods:
$data = [
'users' => [
['name' => 'Alice', 'age' => '30', 'email' => 'alice@example.com'],
['name' => 'Bob', 'age' => '25', 'email' => 'bob@example.com'],
],
];
$accessor = new DataAccessor($data);
// Generic get() - returns mixed
$emails = $accessor->get('users.*.email');
// ['users.0.email' => 'alice@example.com', 'users.1.email' => 'bob@example.com']
// Type-safe getters - strict type conversion with nullable return
$name = $accessor->getString('users.0.name'); // 'Alice'
$age = $accessor->getInt('users.0.age'); // 30 (string β int)
$missing = $accessor->getString('users.0.phone'); // null
// Collection getters for wildcards - returns DataCollection instances
$ages = $accessor->getIntCollection('users.*.age'); // DataCollection<int>
$names = $accessor->getStringCollection('users.*.name'); // DataCollection<string>
// Transformation methods - filter, map, reduce directly on DataAccessor
$filtered = $accessor->filter(fn($user) => $user['age'] > 25); // [['name' => 'Alice', ...]]
$mapped = $accessor->map(fn($user) => $user['name']); // ['Alice', 'Bob']
$sum = $accessor->reduce(fn($carry, $user) => $carry + $user['age'], 0); // 55
// first() and last() with optional callback
$firstUser = $accessor->first(); // ['name' => 'Alice', ...]
$lastAdult = $accessor->last(fn($user) => $user['age'] >= 18);
// Lazy evaluation for large datasets
foreach ($accessor->lazyFilter(fn($user) => $user['age'] > 25) as $user) {
// Process items one at a time without loading all into memory
}π DataAccessor Documentation
Framework-independent collection class with fluent API. Uses DataAccessor for reading, DataMutator for writing, and DataFilter for SQL-like querying:
use event4u\DataHelpers\DataCollection;
$collection = DataCollection::make([1, 2, 3, 4, 5]);
// Filter, map, reduce with method chaining (delegates to DataAccessor)
$result = $collection
->filter(fn($item) => $item > 2) // [3, 4, 5]
->map(fn($item) => $item * 2) // [6, 8, 10]
->reduce(fn($carry, $item) => $carry + $item, 0); // 24
// Dot-notation read access (via DataAccessor)
$collection = DataCollection::make([
['user' => ['name' => 'Alice', 'age' => 30]],
['user' => ['name' => 'Bob', 'age' => 25]],
]);
$name = $collection->get('0.user.name'); // 'Alice'
// Dot-notation write access (via DataMutator) - modifies in-place
$collection
->set('0.user.city', 'Berlin')
->merge('1.user', ['city' => 'Munich', 'country' => 'Germany'])
->transform('0.user.name', fn($name) => strtoupper($name));
// SQL-like filtering (via DataFilter) - returns new DataCollection
$users = DataCollection::make([
['name' => 'Alice', 'age' => 30, 'city' => 'Berlin'],
['name' => 'Bob', 'age' => 25, 'city' => 'Munich'],
['name' => 'Charlie', 'age' => 35, 'city' => 'Berlin'],
]);
$filtered = $users
->query()
->where('age', '>', 25)
->where('city', 'Berlin')
->orderBy('age', 'DESC')
->get(); // Returns new DataCollection
// Lazy evaluation for large datasets
foreach ($collection->lazyFilter(fn($item) => $item > 2) as $item) {
// Process items one at a time without loading all into memory
}π DataCollection Documentation
Safely modify nested structures:
$data = ['user' => ['profile' => []]];
DataMutator::make($data)
->set('user.profile.name', 'Alice')
->merge('user.profile', ['age' => 30]);
// $data is now modified: ['user' => ['profile' => ['name' => 'Alice', 'age' => 30]]]π DataMutator Documentation
Filter and query data with SQL-like API:
$products = [
['id' => 1, 'name' => 'Laptop', 'category' => 'Electronics', 'price' => 1200],
['id' => 2, 'name' => 'Mouse', 'category' => 'Electronics', 'price' => 25],
['id' => 3, 'name' => 'Monitor', 'category' => 'Electronics', 'price' => 400],
];
$result = DataFilter::query($products)
->where('category', '=', 'Electronics')
->where('price', '>', 100)
->orderBy('price', 'DESC')
->get();
// Result: [Laptop ($1200), Monitor ($400)]Create type-safe, immutable Data Transfer Objects with automatic type casting and multi-format serialization (JSON, XML, YAML, CSV):
use event4u\DataHelpers\SimpleDto\Attributes\NoCasts;
// Default: Automatic type casting enabled
class ReadmeUserDto extends SimpleDto
{
public function __construct(
public readonly string $name,
public readonly string $email,
public readonly int $age,
public readonly AddressDto $address, // Nested DTO (auto-cast by default)
) {}
}
// Automatic type conversion by default
$user = ReadmeUserDto::fromArray([
'name' => 'John',
'email' => 'john@example.com',
'age' => '30', // String "30" β int 30 (automatic)
'address' => ['city' => 'Berlin'], // Array β AddressDto (automatic)
]);
// Disable automatic casting for better performance
#[NoCasts]
class StrictUserDto extends SimpleDto
{
public function __construct(
public readonly string $name,
public readonly int $age, // Must be int, no conversion
public readonly AddressDto $address, // Must be AddressDto instance, no conversion
) {}
}
// Multi-format serialization
$json = $user->toJson(); // JSON
$xml = $user->toXml(); // XML
$yaml = $user->toYaml(); // YAML
$csv = $user->toCsv(); // CSVSimpleDto seamlessly integrates with plain PHP objects (like Zend Framework models or any plain PHP classes):
use event4u\DataHelpers\SimpleDto;
use event4u\DataHelpers\SimpleDto\Attributes\HasObject;
use event4u\DataHelpers\SimpleDto\SimpleDtoObjectTrait;
// Plain PHP object
class Product
{
public int $id;
public string $name;
public float $price;
}
// DTO with plain object integration
#[HasObject(Product::class)]
class ProductDto extends SimpleDto
{
use SimpleDtoObjectTrait;
public function __construct(
public readonly int $id,
public readonly string $name,
public readonly float $price,
) {}
}
// Object β DTO
$product = new Product();
$product->id = 1;
$product->name = 'Laptop';
$product->price = 999.99;
$dto = ProductDto::fromObject($product);
// DTO β Object
$newProduct = $dto->toObject(); // Uses HasObject attributeAlso works with getters/setters:
class Customer
{
private int $id;
private string $name;
public function getId(): int { return $this->id; }
public function setId(int $id): void { $this->id = $id; }
public function getName(): string { return $this->name; }
public function setName(string $name): void { $this->name = $name; }
}
// fromObject() uses getters, toObject() uses setters
$dto = CustomerDto::fromObject($customer);
$newCustomer = $dto->toObject(Customer::class);π Plain Object Integration Guide β’ Example Code
Create ultra-fast, minimalistic DTOs with essential features:
use event4u\DataHelpers\LiteDto;
use event4u\DataHelpers\LiteDto\Attributes\MapFrom;
use event4u\DataHelpers\LiteDto\Attributes\Hidden;
class UserDto extends LiteDto
{
public function __construct(
public readonly string $name,
#[MapFrom('email_address')]
public readonly string $email,
#[Hidden]
public readonly string $password,
) {}
}
$user = UserDto::from([
'name' => 'John',
'email_address' => 'john@example.com',
'password' => 'secret',
]);
$array = $user->toArray();
// ['name' => 'John', 'email' => 'john@example.com']
// password is hiddenPerformance: LiteDto is 7.6x faster than SimpleDto Normal (~2.3ΞΌs vs ~18.5ΞΌs)
Map between different data structures with templates. Supports multi-format output (JSON, XML, YAML, CSV):
$source = [
'user' => ['name' => 'John Doe', 'email' => 'john@example.com'],
'orders' => [
['id' => 1, 'status' => 'shipped', 'total' => 100],
['id' => 2, 'status' => 'pending', 'total' => 50],
['id' => 3, 'status' => 'shipped', 'total' => 200],
],
];
$result = DataMapper::from($source)
->template([
'customer_name' => '{{ user.name }}',
'customer_email' => '{{ user.email }}',
'shipped_orders' => [
'WHERE' => [
'{{ orders.*.status }}' => 'shipped',
],
'ORDER BY' => [
'{{ orders.*.total }}' => 'DESC',
],
'*' => [
'id' => '{{ orders.*.id }}',
'total' => '{{ orders.*.total }}',
],
],
])
->map()
->getTarget();π‘ No-Code Data Mapping: Templates can be stored in a database and created with a drag-and-drop editor - perfect for import wizards, API integrations and ETL pipelines without writing code!
sourceFile(), the root element name is preserved. Always include it in your paths: '{{ company.name }}' for <company><name>...</name></company>.
Simplify common data operations with specialized helper classes:
use event4u\DataHelpers\Helpers\MathHelper;
use event4u\DataHelpers\Helpers\EnvHelper;
// Math operations with precision
$result = MathHelper::add('10.5', '20.3', 2); // 30.8
$average = MathHelper::average([10, 20, 30]); // 20.0
$sum = MathHelper::sum([5, 10, 15]); // 30.0
// Environment variable access with type casting
$debug = EnvHelper::boolean('APP_DEBUG', false);
$port = EnvHelper::integer('APP_PORT', 8080);
$timeout = EnvHelper::float('REQUEST_TIMEOUT', 30.0);Available Helpers:
- MathHelper - Precision math operations using bcmath (add, subtract, multiply, divide, modulo, powerOf, squareRoot, compare, min, max, sum, average, product, time conversions)
- EnvHelper - Type-safe environment variable access with framework detection (get, has, string, integer, float, boolean, array)
- ConfigHelper - Singleton configuration manager with framework detection and dot notation (getInstance, get, getBoolean, getInteger, getFloat, getString, getArray, has, set, reset)
- DotPathHelper - Dot notation path utilities with wildcard support (segments, buildPrefix, isWildcard, containsWildcard)
- ObjectHelper - Deep object cloning with recursion control (copy)
Store templates in database and create mappings without programming:
// Load template from database (created with drag-and-drop editor)
$template = Mappings::find(3)->template;
$result = DataMapper::from($source)
->template($template)
->map()
->getTarget();Perfect for:
- π₯ Import Wizards - Let users map CSV/Excel columns to your data model
- π API Integration - Configure API mappings without code changes
- π’ Multi-Tenant Systems - Each tenant can have custom data mappings
- π Dynamic ETL - Build data transformation pipelines visually
- π Form Builders - Map form submissions to different data structures
π Template-Based Mapping Guide
Map complex nested structures to Eloquent Models or Doctrine Entities:
// Automatic relation detection for Eloquent/Doctrine
$company = new Company();
$result = DataMapper::from($jsonData)
->target($company)
->template([
'name' => '{{ company.name }}',
'departments' => [
'*' => [
'name' => '{{ company.departments.*.name }}',
'budget' => '{{ company.departments.*.budget }}',
],
],
])
->map()
->getTarget();- β Automatic Relation Detection
- β Type Casting (string β int/float/bool)
- β Snake_case β camelCase conversion
- β Nested Wildcards
Transform data with composable filters:
use Tests\Utils\Docu\TrimStrings;
use Tests\Utils\Docu\LowercaseEmails;
use Tests\Utils\Docu\SkipEmptyValues;
$source = ['name' => ' John ', 'email' => 'JOHN@EXAMPLE.COM'];
$mapping = ['name' => '{{ name }}', 'email' => '{{ email }}'];
$result = DataMapper::from($source)
->template($mapping)
->pipeline([
new TrimStrings(),
new LowercaseEmails(),
new SkipEmptyValues(),
])
->map()
->getTarget();
// $result = ['name' => 'John', 'email' => 'john@example.com']Use Twig-like expressions with 18+ built-in filters:
$mapping = [
'name' => '{{ user.firstName | ucfirst }} {{ user.lastName | ucfirst }}',
'email' => '{{ user.email | lower | trim }}',
'role' => '{{ user.role | upper ?? "USER" }}',
];π Template Expressions
Laravel-style fluent interface for building queries:
$result = DataMapper::query()
->source('products', $data)
->where('category', 'Electronics')
->where('price', '>', 100)
->orderBy('price', 'DESC')
->groupBy('category', ['total' => ['COUNT']])
->get();π Query Builder Documentation
Comprehensive documentation with guides, examples and API reference is available at:
π event4u-app.github.io/data-helpers
The documentation includes:
- π Getting Started Guides - Installation, configuration and quick start tutorials
- π§ Main Classes - Detailed guides for DataAccessor, DataMutator, DataMapper and DataFilter
- π― SimpleDto - Type-safe Dtos with validation, casting and collections
- β‘ LiteDto - Ultra-fast, minimalistic Dtos (7.6x faster than SimpleDto)
- π Advanced Features - Template expressions, query builder, pipelines and reverse mapping
- π Framework Integration - Laravel, Symfony and Doctrine integration guides
- π‘ 90+ Code Examples - Runnable examples for every feature
- π Performance Benchmarks - Optimization tips and benchmark results
- π Complete API Reference - Full API documentation for all classes and methods
- β 4700+ tests with comprehensive coverage
- β PHPStan Level 9 - Highest static analysis level
- β 100% type coverage - All methods fully typed
- β Continuous Integration - Automated testing across PHP 8.2, 8.3, 8.4
π Contributing Guide β’ Development Setup
All operations are highly optimized:
- Simple access: ~0.0ΞΌs
- Nested access: ~0.4ΞΌs
- Wildcards: ~1ΞΌs
- SimpleDto #[UltraFast] is up to 12.5x faster than Other Serializer
π Performance Benchmarks β’ Optimization Tips
Contributions are welcome! Please see the Contributing Guide for details.
# Install dependencies
composer install
# Run tests
composer test
# Run quality checks
composer qualityThis package is part of the event4u ecosystem - a comprehensive event management platform. Your sponsorship helps us:
- π Develop event4u - The next-generation event management app
- π¦ Maintain open-source packages - Like this Data Helpers library
- π§ Build new tools - More packages and utilities for the PHP community
- π Improve documentation - Better guides and examples
- π Fix bugs faster - Dedicated time for maintenance and support
Every contribution, no matter how small, makes a difference and is greatly appreciated! π
MIT License. See LICENSE for details.
If this package helps you, please consider:
- β Giving it a star on GitHub
- π Sponsoring the development
- π’ Sharing it with others