Asmir Mustafic
PHP User Group Berlin - November 2017
Bosnia, Italy, Germany
Software Developer
contributed/contributing to:
Serialization is the process of translating data structures or object state
into a format that can be stored or transmitted
and reconstructed later in the same or another computer environment
Wikipedia
class User
{
protected $firstName;
protected $lastName;
public function __construct($firstName, $lastName)
{
$this->firstName = $firstName;
$this->lastName = $lastName;
}
}
$user = new User('Elvis', 'Presley'); // or find it somehow...
echo $serializer->serialize($user);
{
"first_name": "Elvis",
"last_name": "Presley"
}
serialization result
{
"first_name": "Elvis",
"last_name": "Presley"
}
$user = $deserializer->deserialize($serializedRepresentation, User::class);
// $user is instance of User class and contains valid data
PHP ^5.5 || ^7.0
Apache-2 License
Serialize:
Deserialize:
opensource
Started in 2011 by Johannes Schmitt
JMSSerializerBundle (later splitted into two repo)
~120 contributors
~16M downloads on packagist (November 2017)
Not including the bundle and related sub-libraries
v1.9.1 currently
April 4th 2016
November 1st 2017
// create the serializer
$serializer = SerializerBuilder::create()->build();
// our example object
$user = new User('Elvis', 'Presley'); // or find it somehow...
// serialize to json
$json = $serializer->serialize($user, 'json'); // serialization
// deserialize from json into a User object
$user = $serializer->deserialize($json, User::class, 'json'); // deserialization
{
"_id": "5919adb4720fc632f4e9f0dc",
"index": 0,
"guid": "c9c9a1ef-8a78-4acc-95ae-617a6d03db1d",
"isActive": true,
"balance": "$3,623.58",
"picture": "http://placehold.it/32x32",
"age": 23,
"eyeColor": "blue",
"name": {
"first": "Malinda",
"last": "Conley"
},
"email": "malinda.conley@flum.us",
"address": "685 Gerry Street, Jenkinsville, Massachusetts, 3466",
"registered": "Sunday, May 11, 2014 1:39 AM",
"latitude": 29.082485,
"longitude": 77.914309,
"tags": ["dolor", "dolor", "magna", "ipsum", "enim"],
"range": [1,1,5,6,7,9,1,654,965,45,7],
"friends": [
{ "id": 0, "name": "Kristi Swanson" },
{ "id": 1, "name": "Alisa Blair" },
{ "id": 2, "name": "Kelly Daugherty" }
],
"greeting": "Hello, Malinda! You have 7 unread messages.",
"favoriteFruit": "banana"
}
But we do not want to get crazy...
class User
{
protected $first_name;
protected $lastName;
}
{
"first_name": "Elvis",
"last_name": "Presley"
}
(default)
class User
{
protected $first_name;
protected $lastName;
}
{
"firstName": "Elvis",
"lastName": "Presley"
}
class User
{
protected $first_name;
protected $lastName;
}
{
"first_name": "Elvis",
"lastName": "Presley"
}
class User
{
protected $first_name;
/**
* @SerializedName("surname")
*/
protected $lastName;
}
{
"first_name": "Elvis",
"surname": "Presley"
}
interface PropertyNamingStrategyInterface
{
public function translateName(PropertyMetadata $property) : string;
}
class User
{
protected $first_name;
protected $lastName;
protected $email;
}
{
"first_name": "Elvis",
"last_name": "Presley",
"email": "king@rocknroll.com"
}
(default)
/**
* @AccessorOrder("alphabetical")
*/
class User
{
protected $first_name;
protected $lastName;
protected $email;
}
{
"first_name": "Elvis",
"email": "king@rocknroll.com",
"last_name": "Presley"
}
/**
* @AccessorOrder("custom", custom = {"email", "first_name", "lastName"})
*/
class User
{
protected $first_name;
protected $lastName;
protected $email;
}
{
"email": "king@rocknroll.com",
"first_name": "Elvis",
"last_name": "Presley"
}
by default
/**
* @AccessType("public_method")
*/
class User
{
private $name;
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = trim($name);
}
}
class User
{
private $id;
/**
* @Accessor(getter="getTrimmedName",setter="setName")
*/
private $name;
// ...
public function getTrimmedName()
{
return trim($this->name);
}
public function setName($name)
{
$this->name = $name;
}
class User
{
private $id;
/**
* @ReadOnly
*/
private $name;
}
/**
* @ReadOnly
*/
class User
{
private $id;
private $name;
}
class User
{
protected $id;
/**
* @Exclude
*/
protected $name;
}
/**
* @ExclusionPolicy("ALL")
*/
class User
{
protected $id;
/**
* @Expose
*/
protected $name;
}
class User
{
protected $id;
/**
* @Groups({"registered", "me"})
*/
protected $name;
/**
* @Groups({"me"})
*/
protected $password;
}
$context = new SerializationContext();
$context->setGroups(["Default", "registered"]);
$serializer->serialize($user, 'json', $context);
{
"id": 9874,
"name": "Elvis Presley"
}
class User
{
protected $name;
/**
* @Groups({"private"})
*/
protected $email;
/**
* @var User
*/
protected $bestFriend;
}
$context = new SerializationContext();
$context->setGroups([
"Default",
"bestFriend" => ["Default", "private"]
]);
$serializer->serialize($user, 'json', $context);
{
"name": "Elvis Presley",
"best_friend": {
"name": "Sonny West",
"email": "sonny@west.com"
}
}
# note "best_friend" circular ref
new in v1.4
class User
{
/**
* @Until("1.0.x")
*/
private $name;
/**
* @Since("1.1")
* @SerializedName("name")
*/
private $name2;
}
$context = new SerializationContext();
$context->setVersion("1.5.0");
$serializer->serialize($user, 'json', $context);
{
"name": "Elvis Presley"
}
// name is taken from field $name2
class User
{
/**
* @Expose(if="service('firends_manager').isAllowed(object)")
*/
private $email;
}
$serializer->serialize($user, 'json');
new in v1.5
class User
{
private $name;
/**
* @MaxDepth(1)
* @var User[]
*/
private $friends;
/**
* @MaxDepth(2)
* @var Post[]
*/
private $likedPosts;
}
class Post
{
private $title;
/**
* @var User[]
*/
private $author;
}
{
"name": "Elvis Presley",
"friends": [
{"name": "Sonny West"}
],
"liked_posts": [
{
"title": "Elvis will disappear",
"author": {
"name": "Allan Weiss"
}
}
],
}
$context = new SerializationContext();
$context->enableMaxDepthChecks();
$ser->serialize($user, 'json', $context);
class User
{
protected $firstName;
protected $lastName;
/**
* @VirtualProperty()
*/
public function getFullName()
{
return $this->firstName . ' '. $this->lastName;
}
}
{
"first_name": "Elvis",
"last_name": "Presley",
"full_name": "Elvis Presley"
}
/**
* @VirtualProperty("fans",
* exp="service('fan_counter').count(object)"
* )
*/
class User
{
protected $firstName;
protected $lastName;
}
{
"first_name": "Elvis",
"last_name": "Presley",
"fans": 9774565
}
new in v1.6
class User
{
protected $id;
/**
* @Type("string")
*/
protected $name;
}
use Ramsey\Uuid\UuidInterface;
class User
{
/**
* @Type("string")
* @var UuidInterface
*/
protected $id;
}
class User
{
/**
* @Type("xxx\namespace\xxx\User")
* @var User
*/
protected $friend;
}
class User
{
/**
* @Type("array")
* @var User[]
*/
protected $friends = array();
}
class User
{
protected $name;
/**
* @Type("array<xxx\namespace\xxx\User>")
* @var User[]
*/
protected $friends = array();
}
{
"name": "Elvis Presley",
"friends": [
{"name":"Sonny West", ...},
{"name":"Sonny West", ...},
...
]
}
new in v1.7
class User
{
protected $name;
/**
* @Type("array<string,xxx\namespace\xxx\User>")
* @var User[]
*/
protected $friends = array();
}
{
"name": "Elvis Presley",
"friends": {
"friend1": {"name":"Sonny West", ...},
"friend2": {"name":"Sonny West", ...},
...
}
}
new in v1.7
class User
{
/**
* @Type("DateTime<'d-m-Y'>")
* @var \DateTime
*/
protected $updated;
/**
* @Type("DateTimeImmutable<'d-m-Y', 'UTC'>")
* @var \DateTimeImmutable
*/
protected $created;
}
use Doctrine\Common\Collections\Collection;
class User
{
/**
* @Type("ArrayCollection<string,xxx\namespace\xxx\User>")
* @var Collection
*/
protected $friends;
}
class User
{
/**
* @Type("MyType")
* @var ???
*/
protected $image;
}
$image can be any type you want
(resources too)
(handler)
class MyHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods()
{
return [
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'MyType',
'method' => 'imageToJson',
],
];
}
public function imageToJson(JsonSerializationVisitor $v, $img, array $type, Context $ctx)
{
return base64_encode(something_cool($image));
}
}
class MyEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
['event' => 'serializer.pre_serialize',
'method' => 'preSerialize'],
['event' => 'serializer.post_deserialize',
'method' => 'postDeserialize', 'format' => 'json'],
['event' => 'serializer.post_deserialize',
'method' => 'postDeserialize', 'class' => 'Foo')]
];
}
public function preSerialize(JMS\Serializer\EventDispatcher\PreSerializeEvent $event)
{
// do something
}
public function postDeserialize(JMS\Serializer\EventDispatcher\PreSerializeEvent $event)
{
// do something else
}
}
# User.yml
User:
properties:
name:
exclude: true
email:
type: string
# User.xml
<serializer>
<class name="User">
<property name="name" exclude="true" />
<property name="email" type="string" />
</class>
</serializer>
class BaseUser
{
protected $name;
}
class AdvancedUser extends BaseUser
{
protected $email;
}
# AdvancedUser.yml
AdvancedUser:
properties:
name:
exclude: true
email:
type: string
class BaseUser
{
protected $name;
}
class AdvancedUser extends BaseUser
{
protected $email;
}
# BaseUser.yml
BaseUser:
properties:
name:
exclude: true
# AdvancedUser.yml
AdvancedUser:
properties:
email:
type: string
(and YAML)