-
Notifications
You must be signed in to change notification settings - Fork 0
Serialization
A Serialization is attached to a model and permit to serialize/deserialize (save/load) objects in/from a specific output/input. For example you have defined a manifest Test\Person and you want to serialize persons in sql database. To do so, you have to define table name and database connection by building serialization manifest file.
When it's done, you're able to serialize/deserialize objects. for more details see Object serialization chapter.
Serializations manifests may be defined in XML, JSON or YAML format (depends on manifest format defined in Configuration file). For each example we will illustrate XML and JSON format. YAML is quite same as JSON, we will only write an complete example at the end.
In this file you have to specify the serialization manifest version to determine witch parser will be used to parse the document. There is currently two allowed version 2.0 and 3.0. Only version 3.0 is documented.
<manifest version="3.0"/>{
"version": "3.0"
}You have to specify the manifest name. The name must be a fully qualified name, in other words it must contain namespace.
<manifest version="3.0" name="Test\Person"/>{
"version": "3.0",
"name": "Test\\Person"
}Warning! due to JSON format you have to put double slash (\\).
Serialization node contain the informations on the way you want to serialize objects (in SQL database, in json file...). There are three way to define the serialization to use for related model objects :
- the serialization settings with node
settings(for settings defined in current file). - the serialization settings with node
foreign_settings(for settings defined in another file). - the serialization unit class with attribute
serialization_unit_class.
Serialization settings are described by their own manifest and are instanciated as Comhon Objects. Now we will describe and explain all availables serializations settings.
File serialization permit to store objects in files. It is available only for objects that have id property. It is attached to model Comhon\File that is described by manifest here. In fact, Comhon\File is not usable to serialize an object (consider it like an abstract class), but there are serializations that extends from this one : Comhon\JsonFile and Comhon\XmlFile.
A Comhon\File serialization must be described in settings node (foreign_settings is not available).
This serialization permit to store objects in JSON files. It is available only for objects that have id property. It is attached to model Comhon\JsonFile that is described by manifest here.
This serialization permit to store objects in XML files. It is available only for objects that have id property. It is attached to model Comhon\XmlFile that is described by manifest here.
As said before, Comhon\JsonFile and Comhon\XmlFile extends from Comhon\File manifest. In fact they are exactly the same, they have two properties inherited from Comhon\File :
-
dir_paththat define the folder where files will be stored -
file_namethat define the names of files that will store all serialized objects
Each object will be serialized in intermediate folder identified by the object id.
Model Test\MyModel has following serialization file :
<root name="Test\MyModel" version="3.0">
<serialization>
<settings dir_path="/asolute/path/to/folder" file_name="file_name.json" inheritance-="Comhon\File\XmlFile"/>
</serialization>
</root>{
"name": "Test\\MyModel",
"version": "3.0",
"serialization": {
"settings": {
"dir_path": "\/asolute\/path\/to\/folder",
"file_name": "file_name.json",
"inheritance-": "Comhon\\File\\XmlFile"
}
}
}An object attached to model Test\MyModel with id an_id, will be saved in file at :
/asolute/path/to/folder/an_id/file_name.json
This serialization permit to store objects in SQL database. It is attached to model Comhon\SqlTable that is described by manifest here.
A Comhon\SqlTable serialization may be described in settings node or foreign_settings node.
Model Comhon\SqlTable has two properties :
-
namethat define the table name (specify schemamy_schema.my_tableif you use a postgresql database) -
databasethat define the database that own the table.
Let's explain database property :
It is attached to model Comhon\SqlDatabase that is described by manifest here.
It is a foreign property so it contain only an id that refer to a database object serialized elsewhere.
In Comhon\SqlDatabase manifest you can see a property DBMS, it permit to identify your database management system. Comhon! currently manage followings DBMS :
- mysql
- pgsql
Comhon\SqlTable and Comhon\SqlDatabase have their own serialization. Actually they use JSON file serialization. SQL tables descriptions MAY be serialized in json file and database(s) descriptions MUST be serialized in JSON files. Take a look at Configuration page to see in which folder these Json files are saved and how to configure it.
- Sql tables MAY be saved in files named
table.jsonin intermediate folder named with table id (id property is the table name) - Sql databases MUST be saved in files named
database.jsonin intermediate folder named with database id
A right sql serialization file looks like :
- with
settingsnode
<root name="Test\MyModel" version="3.0">
<serialization>
<settings table="my_table" database="my_db" inheritance-="Comhon\SqlTable"/>
</serialization>
</root>{
"name": "Test\\MyModel",
"version": "3.0",
"serialization": {
"settings": {
"table": "my_table",
"database": "my_db",
"inheritance-": "Comhon\\SqlTable"
}
}
}- or with
foreign_settingsnode
<root name="Test\MyModel" version="3.0">
<serialization>
<foreign_settings id="my_table" inheritance-="Comhon\SqlTable"/>
</serialization>
</root>{
"name": "Test\\MyModel",
"version": "3.0",
"serialization": {
"foreign_settings": {
"id": "my_table",
"inheritance-": "Comhon\\SqlTable"
}
}
}In case of using foreign_settings node, the table my_table object must be serialized in a file that would looks like :
{
"table": "my_table",
"database": "my_db"
}In both case, you must define the database informations in a file that would looks like :
{
"id": "my_db",
"DBMS": "mysql",
"host": "localhost",
"name": "database",
"user": "my_user",
"password": "my_passord",
"options": {
"charset": "utf8",
"timezone": "UTC"
}
}- Path to table file would looks like :
/my/configured/tables/path/my_table/table.json. - Path to database file would looks like :
/my/configured/databases/path/my_db/database.json.
Comhon! is optimized to load only one time serializations. For example if you have two tables that refer the same database, and if you use them in a single script execution, tables will share the same instance of database.
You can define your own serialization by using a PHP class. To do so, you have to specify serialization_unit_class attribute.
<root name="Test\MyModel" version="3.0">
<serialization serialization_unit_class="\My\FullyQualifiedName\Serialization\Class"/>
</root>{
"name": "Test\\MyModel",
"version": "3.0",
"serialization": {
"serialization_unit_class": "\\My\\FullyQualifiedName\\Serialization\\Class"
}
}Your class MUST be an instance of SerializationUnit so it must directly or indirectly extends from it. And it must contain at least saveObject, loadObject, deleteObject and hasIncrementalId methods.
Your class may extends ValidatedSerializationUnit. This class automatically verify if given object in parameter may use current serialization. In this case your class must contain at least getType, _saveObject, _loadObject, _deleteObject and hasIncrementalId methods.
this information is used if you have several models that have the same serialization. It permit to bind model with deserialized object.
For example you have a SQL table person with a column gender that permit to differentiate men and women, and you have defined manifests of Test\Person\Woman and Test\Person\Man that extends Test\Person. You have to define inheritance key as gender to bind Test\Person\Woman or Test\Person\Man model to deserialized object.
<manifest name="Test\Person" version="3.0">
<serialization inheritance_key="gender">
<foreign_settings id="`person`" inheritance-="Comhon\SqlTable"/>
</serialization>
</manifest>{
"name": "Test\\Person",
"version": "3.0",
"serialization": {
"inheritance_key": "gender",
"foreign_settings": {
"id": "`person`",
"inheritance-": "Comhon\\SqlTable"
}
}
}inheritance_key will be automatically set during serialization (save) and automatically taken in account during deserialzation (load).
Note that inheritance_key value must be an existing model name.
/------------------------------------------------\
| firstname | lastname | age | gender |
|------------------------------------------------|
| jane | doe | 24 | Test\Person\Woman |
| john | doe | 12 | Test\Person\Man |
\------------------------------------------------/
Some properties of a model may be (or not) serialized in a specific way. The properties node permit to list them. The properties node is an array and each property must have a name defined in corresponding Model manfiest.
<root name="Test\Person" version="3.0">
<properties>
<property property_name="age"/>
</properties>
</root>{
"name": "Test\\Person",
"version": "3.0",
"properties": [
{
"property_name": "age"
}
]
}By default all properties are serializable. But you may define a property in a model and don't want it to be serialized.To do so, you have to specify is_serializable attribute.
<root name="Test\Person" version="3.0">
<properties>
<property property_name="age" is_serializable="0"/>
</properties>
</root>{
"name": "Test\\Person",
"version": "3.0",
"properties": [
{
"property_name": "age",
"is_serializable": false
}
]
}Some serialization doesn't manage certain characters so you can replace a property name when you serialize your Object. For example pgsql doesn't manage columns names with uppercase (*), so if you have a property name APropertyName you can define a serialization name a_property_name that will match with your column name.
(*) Important ! In fact pgsql allow columns names with uppercase by adding " to escape column name. But Comhon will not escape columns names during request because it would complicate execution and there's no reason not to follow pgsql standard.
<root name="Test\Person" version="3.0">
<properties>
<property property_name="firstName" serialization_name="first_name"/>
</properties>
</root>{
"name": "Test\\Person",
"version": "3.0",
"properties": [
{
"property_name": "firstName",
"serialization_name": "first_name"
}
]
}serialization_name can't coexist with serialization_names.
Serialization names is available only for foreign properties that have a model with several id properties. It might be used when object is serialized in database table that contain composite foreign key(s) (foreign key with several columns).
serialization_names node is an associative array, each key is the foreign property id name and each value is "local" serialization name (SQL column name for example).
<manifest name="Test\MyModel" version="3.0">
<properties/>
<property property_name="my_foreign_property_with_several_id">
<serialization_names>
<serialization_name key-="id1">my_column_foreign_id_one</serialization_name>
<serialization_name key-="id2">my_column_foreign_id_two</serialization_name>
</serialization_names>
</property>
</properties>
</manifest>{
"name": "Test\\MyModel",
"version": "3.0",
"properties": [
{
"property_name": "my_foreign_property_with_several_id",
"serialization_names": {
"id1": "my_column_foreign_id_one",
"id2": "my_column_foreign_id_one_two"
}
}
]
}serialization_names can't coexist with serialization_name.
If a model is loaded, Comhon! is not able to know which are children models. For example if model Test\Person is loaded Comhon! is not able to know that Test\Person\Man exists and extends from it. inheritance_values node permit to list, if needed, all inherited models that share same serializations.
Inheritance values are used during object requesting. Let's define an example to have better comprehension. We have models that share same SQL serialization :
Test\Person-
Test\Person\Manthat extends fromTest\Person -
Test\Person\Womanthat extends fromTest\Person -
Test\Person\PregnantWomanthat extends fromTest\Person\Woman
Some men, women and pregnant women are stored in SQL table and an inheritance key permit to differentiate them.
If I want to request women, that means implicitly that I request women AND pregnant women. But if inheritance values are not defined, Comhon! can't have this information only with Test\Person\Woman model. So inheritance values of model Test\Person\Woman must be set and should look like :
<manifest name="Sample\Person\Woman" version="3.0">
<inheritance_values>
<model>Test\Person\Woman</model>
<model>Test\Person\PregnantWomanWoman</model>
</inheritance_values>
</manifest>{
"name": "Sample\\Person\\Woman",
"version": "3.0",
"inheritance_values": [
"Sample\\Person\\Woman",
"Sample\\Person\\PregnantWomanWoman"
]
}Define all inheritance values by hand may be difficult but hopefully Comhon! provide a CLI script that might be called from a terminal to update automatically all inheritance values.
to call script from your project folder where vendor folder might be found, type following line :
> php vendor/comhon-project/comhon/src/Comhon/Executable/ModelBinder.php
to get help and know how to use script, type following line :
> php vendor/comhon-project/comhon/src/Comhon/Executable/ModelBinder.php -h
If a model inherit from another, it will inherit it serialization automatically. So if you want to keep same serialization you don't have to create a serialization manifest for inherited model. For example We can define a serialization on Test\Person model, and Test\Woman and Test\Man will have automatically same serialization. If an inherited model have a serialization manifest file but without serialization node, it inherit serialization too.
If a model inherit from several models (multiple inheritance), it will inherit the serialtization of the first parent model.
If you want a different serialization for inherited model you just have to create a serialization manifest and define serialization node for this model, it will overwrite parent serialization.
If you don't want serialization but parent model has serialization, you have to specify share_parent_serialization attribute.
<root name="Test\MyModel" version="3.0" share_parent_serialization="0"/>{
"name": "Test\\MyModel",
"version": "3.0",
"share_parent_serialization": false
}As manifests, serializations manifests are autoloaded. All serializations manifests files must be named serialization.json or serialization.xml (depends on manifest format defined in Configuration file).
By default Comhon! will search serialization manifest file in same folder than manifest file.
For example if manifest is at :
/my/directory/manifests/Person/manifest.json
Comhon! will search serialization manifest at :
/my/directory/manifests/Person/serialization.json
If you want to store serializations manifests in a different directory than manifest you can do so by specifying a directory for serializations manifests in Configuration file.
For example :
"autoload": {
"manifest":{
"Test":"../manifests/manifest"
},
"serialization":{
"Test":"../manifests/serialization"
}
}
manifests in namespace Test are stored in directory :
../manifests/manifest
serializations manifests in namespace Test are stored in directory :
../manifests/serialization
If serialization manifest file is found, A serialization instance will be attached to model instance. And you will be able to serialize/deserialize objects.
<root name="Test\Person" version="3.0">
<serialization inheritance_key="gender">
<foreign_settings id="person" inheritance-="Comhon\SqlTable"/>
</serialization>
<properties>
<property property_name="firstName" serialization_name="first_name"/>
<property property_name="lastName" serialization_name="last_name"/>
<property property_name="birthDate" serialization_name="birth_date"/>
<property property_name="age" is_serializable="0"/>
<property property_name="birthPlace" serialization_name="birth_place"/>
<property property_name="bestFriend" serialization_name="best_friend"/>
<property property_name="father" serialization_name="father_id"/>
<property property_name="mother" serialization_name="mother_id"/>
</properties>
</root>{
"name": "Test\\Person",
"version": "3.0",
"serialization": {
"inheritance_key": "gender",
"foreign_settings": {
"id": "person",
"inheritance-": "Comhon\\SqlTable"
}
},
"properties": [
{
"property_name": "firstName",
"serialization_name": "first_name"
},
{
"property_name": "lastName",
"serialization_name": "last_name"
},
{
"property_name": "birthDate",
"serialization_name": "birth_date"
},
{
"property_name": "age",
"is_serializable": false
},
{
"property_name": "birthPlace",
"serialization_name": "birth_place"
},
{
"property_name": "bestFriend",
"serialization_name": "best_friend"
},
{
"property_name": "father",
"serialization_name": "father_id"
},
{
"property_name": "mother",
"serialization_name": "mother_id"
}
]
}name: Test\Person
version: '3.0'
serialization:
inheritance_key: gender
foreign_settings:
id: person
inheritance-: Comhon\SqlTable
properties:
-
property_name: firstName
serialization_name: first_name
-
property_name: lastName
serialization_name: last_name
-
property_name: birthDate
serialization_name: birth_date
-
property_name: age
is_serializable: false
-
property_name: birthPlace
serialization_name: birth_place
-
property_name: bestFriend
serialization_name: best_friend
-
property_name: father
serialization_name: father_id
-
property_name: mother
serialization_name: mother_id