kingson-de / marshal-serializer
Marshal is serializing / marshalling data structures to the desired format. It is also deserializing / unmarshalling the format back to the data structures.
Requires
- php: ^7.0
Requires (Dev)
- phpunit/phpunit: ^6.5
This package is auto-updated.
Last update: 2025-04-15 12:10:01 UTC
README
Introduction
Marshal is serializing / marshalling data structures to the desired format. It is also deserializing / unmarshalling the format back to the data structures.
Especially useful for building the raw response for web services which then can be formatted to JSON for example.
If you need to serialize directly to a format, use the appropriate Marshal library:
Installation
Easiest way to install the library is via composer:
composer require kingson-de/marshal-serializer
The following PHP versions are supported:
- PHP 7.0
- PHP 7.1
- PHP 7.2
- PHP 7.3
Execute tests
Just run:
composer test
Or without code coverage:
composer quicktest
Usage
Mappers
The first thing to do is to create a mapper that takes care of mapping your entities / models to the correct format.
You always need to inherit from the abstract Mapper class and implement a map
function with your type hinting.
There is also the option to use directly a callable to map data. This will be explained later.
It is always possible to use a callable in a mapper or vice versa.
<?php use KingsonDe\Marshal\AbstractMapper; class UserMapper extends AbstractMapper { public function map(User $user) { return [ 'username' => $user->getUsername(), 'email' => $user->getEmail(), 'birthday' => $user->getBirthday()->format('Y-m-d'), 'followers' => count($user->getFollowers()), ]; } }
Data Structures
Next step is to create the desired data structure either being an item/object or a collection.
Item/Object
<?php use KingsonDe\Marshal\Data\Item; $item = new Item(new UserMapper(), $user);
Collection
<?php use KingsonDe\Marshal\Data\Collection; $userCollection = [$user1, $user2, $user3]; $item = new Collection(new UserMapper(), $userCollection);
Serializing / Marshalling
The final step is to map the data structures to the actual format.
<?php use KingsonDe\Marshal\Marshal; $data = Marshal::serialize($item);
You are also not forced to create data structures on your own, you can use the appropriate Marshal functions instead:
<?php use KingsonDe\Marshal\Marshal; $data = Marshal::serializeItem($mapper, $model); // or $data = Marshal::serializeCollection($mapper, $modelCollection); // or $data = Marshal::serializeCollectionCallable(function (User $user) { return [ 'username' => $user->getUsername(), 'email' => $user->getEmail(), 'birthday' => $user->getBirthday()->format('Y-m-d'), 'followers' => count($user->getFollowers()), ]; }, $modelCollection);
Symfony Example
<?php use KingsonDe\Marshal\Data\Item; use KingsonDe\Marshal\Marshal; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; class UserController extends Controller { public function indexAction(User $user) { $item = new Item(new UserMapper(), $user); $data = Marshal::serialize($item); return new JsonResponse($data); } }
Advanced Mappers
Nested Data Structures
Mappers can even include other mappers with different data structures.
Therefore you can use item
, itemCallable
, collection
or collectionCallable
function from the AbstractMapper class.
<?php use KingsonDe\Marshal\AbstractMapper; class UserMapper extends AbstractMapper { public function map(User $user) { return [ 'username' => $user->getUsername(), 'email' => $user->getEmail(), 'birthday' => $user->getBirthday()->format('Y-m-d'), 'followers' => $this->collection(new FollowerMapper(), $user->getFollowers), 'location' => $this->item(new LocationMapper(), $user->getLocation()), ]; } }
Pass as many parameters as you like to the mappers
<?php use KingsonDe\Marshal\Data\Item; use KingsonDe\Marshal\Marshal; $item = new Item(new UserMapper(), $user, $followers, $location); $data = Marshal::serialize($item);
<?php use KingsonDe\Marshal\AbstractMapper; class UserMapper extends AbstractMapper { public function map(User $user, FollowerCollection $followers, Location $location) { return [ 'username' => $user->getUsername(), 'email' => $user->getEmail(), 'birthday' => $user->getBirthday()->format('Y-m-d'), 'followers' => $this->collection(new FollowerMapper(), $followers), 'location' => $this->item(new LocationMapper(), $location), ]; } }
For collections the first parameter passed is the one which Marshal will use for iterating.
All other parameters in a collection will stay as it is.
For items/objects all parameters retain.
Filter out single item's from the collection
Collection mappers can discard single item's by returning null
.
<?php use KingsonDe\Marshal\AbstractMapper; class UserMapper extends AbstractMapper { public function map(User $user) { if ($user->isPrivate()) { return null; } return [ 'username' => $user->getUsername(), ]; } }
Deserializing / Unmarshalling
To transform the actual format back to your structure use Marshal's deserialize functions. You need a class extending the AbstractObjectMapper which will be passed to the deserialize function.
<?php use KingsonDe\Marshal\AbstractObjectMapper; use KingsonDe\Marshal\Data\FlexibleData; use KingsonDe\Marshal\Example\Model\User; class UserObjectMapper extends AbstractObjectMapper { /** * @inheritdoc * * @return User */ public function map(FlexibleData $flexibleData, ...$additionalData) { return new User( $flexibleData['id'] ?? 0, $flexibleData['email'] ?? '', $flexibleData->find('username', '') ); } }
<?php use KingsonDe\Marshal\Marshal; $data = Marshal::serializeItem(new UserMapper(), $user); $user = Marshal::deserialize(new UserObjectMapper(), $data);
Another option would be to use the deserializeCallable function.
<?php use KingsonDe\Marshal\Marshal; $data = Marshal::serializeItem(new UserMapper(), $user); $user = Marshal::deserializeCallable(function (FlexibleData $flexibleData) { return new User( $flexibleData->get('id'), $flexibleData->get('email'), $flexibleData->get('username') ); }, $data);
License
This project is released under the terms of the Apache 2.0 license.