Skip to content
comhon-project edited this page Sep 21, 2020 · 41 revisions

Table of Contents

  1. Preamble
  2. Serialization manifest
    1. Version
    2. Name
    3. Serialization node
    4. Serializations settings
      1. File
        1. JSON File
        2. XML File
        3. Manifest explanation
      2. Sql Table
    5. Serialization unit class
    6. Inheritance key
    7. Properties
      1. Serializable
      2. Serialization name
      3. Serialization names
    8. Inheritance values
  3. Inheritance
  4. Autoloading
  5. Serialization Person example

Preamble

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.

Serialization manifest

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.

Version

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"
}

Name

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

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

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

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).

JSON file

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.

XML file

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.

Manifest explanation

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_path that define the folder where files will be stored
  • file_name that define the names of files that will store all serialized objects

Each object will be serialized in intermediate folder identified by the object id.

Example

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

Sql Table

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 :

  • name that define the table name (specify schema my_schema.my_table if you use a postgresql database)
  • database that 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.json in intermediate folder named with table id (id property is the table name)
  • Sql databases MUST be saved in files named database.json in intermediate folder named with database id

Example

A right sql serialization file looks like :

  • with settings node
<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_settings node
<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.

Serialization unit class

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.

Inheritance key

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   |
\------------------------------------------------/

Properties

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"
        }
    ]
}

Serializable

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
        }
    ]
}

Serialization name

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

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.

Inheritance values

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\Man that extends from Test\Person
  • Test\Person\Woman that extends from Test\Person
  • Test\Person\PregnantWoman that extends from Test\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

Inheritance

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
}

Autoloading

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.

Serialization Person example

<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

Clone this wiki locally