baraja-core / serializer
Simple serializer any PHP type or structure to simple scalar array.
Installs: 27 990
Dependents: 1
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 1
Open Issues: 0
pkg:composer/baraja-core/serializer
Requires
- php: ^8.0
Requires (Dev)
- baraja-core/ecommerce-standard: ^0.0
- baraja-core/localization: ^2.0
- nette/utils: ^3.2
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-nette: ^1.0
- phpstan/phpstan-strict-rules: ^1.0
- roave/security-advisories: dev-master
- spaze/phpstan-disallowed-calls: ^2.0
- tracy/tracy: ^2.8
This package is auto-updated.
Last update: 2026-01-04 10:29:43 UTC
README
A simple, secure, and flexible serializer that converts any PHP object or data structure into a simple scalar array, ready to be sent via REST API.
The serializer automatically handles backward and forward compatibility, security concerns, and supports a wide range of PHP types including DTOs, entities, enums, DateTime objects, and more.
π‘ Key Principles
- Zero dependencies - Works standalone without any required external packages
- Security-first - Automatically hides sensitive data (passwords, credit cards, PINs)
- Type-safe - Full support for PHP 8.0+ typed properties and modern features
- Recursion protection - Detects and prevents infinite loops in object graphs
- Depth limiting - Protects against overly deep nested structures (max 32 levels)
- Convention-based - Configurable behavior through the convention system
- Bridge interfaces - Extensible architecture for custom type handling
ποΈ Architecture
The package follows a simple yet powerful architecture with clear separation of concerns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Serializer β
β (Main entry point - singleton or instance-based usage) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β SerializerConvention β
β (Configuration: date format, null handling, hidden keys) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Bridge Interfaces β
β βββββββββββββββββββββββ βββββββββββββββββββββββββββββ β
β β ItemsListInterface β β StatusCountInterface β β
β β (List collections) β β (Status with count) β β
β βββββββββββββββββββββββ βββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Supported Types β
β - Scalars (string, int, float, bool, null) β
β - Arrays (indexed and associative) β
β - Objects (DTOs, entities, stdClass) β
β - DateTimeInterface β
β - UnitEnum (PHP 8.1+) β
β - Nette\Utils\Paginator β
β - Baraja\Localization\Translation β
β - Baraja\EcommerceStandard\DTO\PriceInterface β
β - Objects with __toString() method β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βοΈ Core Components
Serializer
The main class responsible for converting PHP data structures to arrays. It can be used as a singleton via Serializer::get() or instantiated with a custom convention.
Key features:
- Processes objects using reflection to access all properties (including private)
- Automatically skips internal properties (those starting with
_) - Tracks object instances to detect circular references
- Enforces depth limit to prevent stack overflow
SerializerConvention
Configuration class that controls serialization behavior:
| Property | Default | Description |
|---|---|---|
dateTimeFormat |
'Y-m-d H:i:s' |
Format for DateTime serialization |
rewriteTooStringMethod |
true |
Use __toString() for stringable objects |
rewriteNullToUndefined |
false |
Remove null values from output |
keysToHide |
['password', 'passwd', ...] |
Keys containing sensitive data |
Bridge Interfaces
ItemsListInterface - For objects representing a collection of items:
interface ItemsListInterface { /** @return array<int, array<string, mixed>> */ public function getData(): array; }
StatusCountInterface - For status objects with a count (useful for filters, tabs):
interface StatusCountInterface { public function getKey(): string; public function getLabel(): string; public function getCount(): int; }
π¦ Installation
It's best to use Composer for installation, and you can also find the package on Packagist and GitHub.
To install, simply use the command:
$ composer require baraja-core/serializer
You can use the package manually by creating an instance of the internal classes.
Requirements
- PHP 8.0 or higher
- No required dependencies (optional integrations available)
π Basic Usage
Simple DTO Serialization
use Baraja\Serializer\Serializer; class UserDTO { public function __construct( public string $name, public string $email, public int $age, ) { } } $serializer = Serializer::get(); $user = new UserDTO( name: 'Jan Barasek', email: 'jan@example.com', age: 30, ); $result = $serializer->serialize($user); // Result: ['name' => 'Jan Barasek', 'email' => 'jan@example.com', 'age' => 30]
Nested Objects
class AddressDTO { public function __construct( public string $street, public string $city, ) { } } class PersonDTO { public function __construct( public string $name, public AddressDTO $address, ) { } } $person = new PersonDTO( name: 'Jan', address: new AddressDTO(street: 'Main St', city: 'Prague'), ); $result = $serializer->serialize($person); // Result: [ // 'name' => 'Jan', // 'address' => ['street' => 'Main St', 'city' => 'Prague'] // ]
Array Serialization
$data = [ 'users' => [ new UserDTO('Alice', 'alice@example.com', 25), new UserDTO('Bob', 'bob@example.com', 30), ], 'total' => 2, ]; $result = $serializer->serialize($data);
DateTime Handling
class EventDTO { public function __construct( public string $title, public \DateTimeInterface $startDate, ) { } } $event = new EventDTO( title: 'Conference', startDate: new \DateTime('2024-06-15 10:00:00'), ); $result = $serializer->serialize($event); // Result: ['title' => 'Conference', 'startDate' => '2024-06-15 10:00:00']
Enum Serialization (PHP 8.1+)
enum Status: string { case Active = 'active'; case Inactive = 'inactive'; } class ItemDTO { public function __construct( public string $name, public Status $status, ) { } } $item = new ItemDTO(name: 'Product', status: Status::Active); $result = $serializer->serialize($item); // Result: ['name' => 'Product', 'status' => 'active']
π‘οΈ Security Features
Automatic Password Protection
The serializer automatically detects and hides sensitive keys. When a sensitive key is found, its value is replaced with *****:
class LoginDTO { public function __construct( public string $username, public string $password, ) { } } $login = new LoginDTO(username: 'admin', password: 'secret123'); $result = $serializer->serialize($login); // Result: ['username' => 'admin', 'password' => '*****']
Default hidden keys: password, passwd, pass, pwd, creditcard, credit card, cc, pin
Exception: BCrypt hashes (format $2[ayb]$...) are allowed through, as they are already securely hashed.
Internal Property Protection
Properties starting with underscore (_) are automatically excluded from serialization:
class EntityDTO { public function __construct( public string $name, public string $_internalId, // Will be excluded ) { } }
Recursion Detection
The serializer tracks object instances and throws an exception if circular references are detected:
class Node { public function __construct( public string $name, public ?Node $parent = null, ) { } } $node = new Node('A'); $node->parent = $node; // Circular reference $serializer->serialize($node); // Throws: InvalidArgumentException with recursion warning
π§ Advanced Usage
Custom Convention
Create a custom convention by extending SerializerConvention:
use Baraja\Serializer\Serializer; use Baraja\Serializer\SerializerConvention; class CustomConvention extends SerializerConvention { private string $dateTimeFormat = 'c'; // ISO 8601 private bool $rewriteNullToUndefined = true; } $convention = new CustomConvention(); $serializer = new Serializer($convention);
Using Bridge Interfaces
ItemsListInterface
Implement this interface for paginated or list results:
use Baraja\Serializer\Bridge\ItemsListInterface; class UserList implements ItemsListInterface { /** @param UserDTO[] $users */ public function __construct( private array $users, ) { } public function getData(): array { return array_map( fn(UserDTO $user) => [ 'name' => $user->name, 'email' => $user->email, ], $this->users, ); } }
Convention: ItemsListInterface objects must be placed in a key named items.
StatusCountInterface
Useful for filter tabs or status counts:
use Baraja\Serializer\Bridge\StatusCountInterface; class OrderStatus implements StatusCountInterface { public function __construct( private string $key, private string $label, private int $count, ) { } public function getKey(): string { return $this->key; } public function getLabel(): string { return $this->label; } public function getCount(): int { return $this->count; } } $statuses = [ new OrderStatus('pending', 'Pending', 5), new OrderStatus('completed', 'Completed', 42), ]; $result = $serializer->serialize($statuses); // Result: [ // ['key' => 'pending', 'label' => 'Pending', 'count' => 5], // ['key' => 'completed', 'label' => 'Completed', 'count' => 42], // ]
Nette Paginator Support
If nette/utils is installed, Paginator objects are automatically serialized:
use Nette\Utils\Paginator; $paginator = new Paginator(); $paginator->setItemCount(100); $paginator->setItemsPerPage(10); $paginator->setPage(3); $result = $serializer->serialize(['paginator' => $paginator]); // Result: [ // 'paginator' => [ // 'page' => 3, // 'pageCount' => 10, // 'itemCount' => 100, // 'itemsPerPage' => 10, // 'firstPage' => 1, // 'lastPage' => 10, // 'isFirstPage' => false, // 'isLastPage' => false, // ] // ]
Convention: Paginator objects must be placed in a key named paginator.
Translation Support
If baraja-core/localization is installed, Translation objects are converted to strings:
use Baraja\Localization\Translation; $translation = new Translation(['en' => 'Hello', 'cs' => 'Ahoj']); $result = $serializer->serialize(['greeting' => $translation]); // Result: ['greeting' => 'Hello'] (based on current locale)
Price Support
If baraja-core/ecommerce-standard is installed, PriceInterface objects are serialized:
// Assuming $price implements PriceInterface $result = $serializer->serialize(['price' => $price]); // Result: [ // 'price' => [ // 'value' => '199.00', // 'currency' => 'USD', // 'html' => '$199.00', // 'isFree' => false, // ] // ]
β οΈ Conventions and Constraints
Enforced Conventions
- ItemsListInterface must be in key
items - Paginator must be in key
paginator - Maximum depth is 32 levels
- Properties starting with
_are excluded
Error Handling
The serializer throws exceptions for:
- LogicException: Structure depth exceeds 32 levels
- InvalidArgumentException: Circular reference detected
- InvalidArgumentException: ItemsListInterface not in
itemskey - InvalidArgumentException: Paginator not in
paginatorkey - InvalidArgumentException: Unsupported value type
β οΈ Security Logging
When a sensitive key with a non-BCrypt value is detected, the serializer logs a critical warning via Tracy Debugger (if available):
Security warning: User password may have been compromised!
The Baraja API prevented passwords being passed through the API in a readable form.
This helps identify potential security issues during development.
π₯ Author
Jan Barasek - https://baraja.cz
π License
baraja-core/serializer is licensed under the MIT license. See the LICENSE file for more details.