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

Table of Contents

  1. Manifest description
    1. Version
    2. Name
    3. Properties
      1. Basic property
      2. Id property
      3. Object property
      4. Foreign property
      5. Array property
      6. Aggregation property
      7. Auto increment property
      8. Default property value
      9. Required property
      10. Dependencies
      11. Conflicts
    4. Restrictions
      1. Enumeration
      2. Interval
      3. Pattern
      4. Regular Expression
      5. Length
      6. Size
      7. Not null
      8. Not empty
      9. Model name
    5. Local manifest
    6. Inheritance
    7. Abstract model
    8. Share id
    9. Isolated value
    10. Associate a class object
    11. Main
  2. Namespace
  3. Autoloading
  4. Manifest Person example

Manifest description

A Manifest permit to describe a concept by listing its properties. Manifests may be defined in XML, JSON or YAML format. 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.
To explain what is a Manifest we will build a manifest that describe a person as example.

Version

You have to specify the manifest version to determine which 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.
Namespaces and autoloading are explained in next chapters.

<manifest version="3.0" name="Test\Person"/>
{
    "version": "3.0",
    "name": "Test\\Person"
}

Warning! due to JSON format you have to put double slash (\\).

Properties

Properties are listed in properties node.

<manifest version="3.0" name="Test\Person">
    <properties>
        ...
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": []
}

Basic property

A property must ave at least name and inheritance- attributes. inheritance- value determine the type of property (a string, an object, an array...).
Available inheritance- values are :

  • Comhon\Manifest\Property\String for string properties
  • Comhon\Manifest\Property\Integer for integer properties
  • Comhon\Manifest\Property\Index for index properties (integer value supperior than 0)
  • Comhon\Manifest\Property\Float for float properties
  • Comhon\Manifest\Property\Percentage for percentage properties
  • Comhon\Manifest\Property\Boolean for boolean properties
  • Comhon\Manifest\Property\DateTime for date time properties
  • Comhon\Manifest\Property\Object for object properties (explained in next chapter)
  • Comhon\Manifest\Property\Array for array properties (explained in next chapter)
  • Comhon\Manifest\Property\Aggregation for specific array properties (explained in next chapter)
<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="birthDate" inheritance-="Comhon\Manifest\Property\DateTime"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        }
        {
            "name": "birthDate",
            "inheritance-": "Comhon\\Manifest\\Property\\DateTime"
        }
    ]
}

Id property

We want an id to find easily a person, so we need to add an id property.
An id property is a part of a model id. Commonly models have only one id property but you can define several id properties.
To define a property as id property, you just have to add an attribute is_id (id must be a float, integer or string).

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="id" inheritance-="Comhon\Manifest\Property\Integer" is_id="1"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "id",
            "inheritance-": "Comhon\\Manifest\\Property\\Integer",
            "is_id": true
        }
    ]
}

Object property

An object property is a property that refer to an object defined in a manifest.
For example, a person may have a home. And a home would be described by a manfiest named Test\House.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="home" model="\Test\House" inheritance-="Comhon\Manifest\Property\Object"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "home",
            "model": "\\Test\\House",
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        }
    ]
}

model attribute is a value with relative or absolute namespace (explained in namespace chapter).

Foreign property

A Foreign property is an object property that contain the key is_foreign, it refers another Object that has an existence elsewhere. Like described before Person may have a property home, and this property is basically a foreign property because a house may exist without it's owner.
Often a foreign value is serialized in a different place, for example if we store Person and House in SQL database, they would be in different tables and Person table would only refer to a House id.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="home" model="\Test\House" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "home",
            "model": "\\Test\\House",
            "is_foreign": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        }
    ]
}

Array property

We want to have a property middleNames. actually a person can have a second name, third name... so we can define an array property to store these names.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="middleNames" inheritance-="Comhon\Manifest\Property\Array">
            <values name="middleName" inheritance-="Comhon\Manifest\Value\String"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "middleNames",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "middleName",
                "inheritance-": "Comhon\\Manifest\\Value\\String"
            }
        }
    ]
}

The values node describe what array may contain. this node is like a property node but may be found only in arrays. each properties inheritance- are available for values except aggregation, but the namespace is different and must be Comhon\\Manifest\\Value.
The name attribute is the name of an element (basically it's the singular of property name).

By default, an array property describes an indexed array, but you can define an associative array by adding is_associative attribute.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="middleNames" inheritance-="Comhon\Manifest\Property\Array" is_associative="1">
            <values name="middleName" inheritance-="Comhon\Manifest\Value\String"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "middleNames",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "is_associative": true,
            "values": {
                "name": "middleName",
                "inheritance-": "Comhon\\Manifest\\Value\\String"
            }
        }
    ]
}

Aggregation property

Now instead having a unique home we want a person able to have several homes.

One way to do is to define an array property that contain foreign objects values.
The other way to do is to define an aggregation. An aggregation is usually used when two models are serialized (saved) in different "places". In our case, models Test\Person and Test\House would be serialized in different SQL tables, and table for model Test\House would have a column that reference the owner like owner_id.

In aggregation property the model used in values node must have a reference to "parent" model to know how to link models (for example model Test\House should have a property owner with model Test\Person). The link must be described in aggregation property under node aggregations (actually link might be defined on several properties, see children property in manifest example).

In aggregation property, the value is necessarily a foreign object, so no need to specify inheritance- and is_foreign.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="homes" inheritance-="Comhon\Manifest\Property\Aggregation">
            <values name="home" model="Test\House"/>
            <aggregations>
                <aggregation>owner</aggregation>
            </aggregations>
        </property>
    </properties>
</manifest>
<manifest version="3.0" name="Test\House">
    <properties>
        <property name="id" is_id="1" inheritance-="Comhon\Manifest\Property\Integer"/>
        <property name="owner" model="\Test\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        ...
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "homes",
            "values": {
                "name": "home",
                "model": "Test\\House"
            },
            "aggregations": [
                "owner"
            ],
            "inheritance-": "Comhon\\Manifest\\Property\\Aggregation"
        }
    ]
}
{
    "version": "3.0",
    "name": "Test\\House",
    "properties": [
        {
            "name": "id",
            "is_id": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Integer"
        }
        {
            "name": "owner",
            "model": "\\Test\\Person",
            "is_foreign": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        }
    ]
}

Auto increment property

An index property may be defined as auto incremental. It permit to a public client to know if a property is automatically set when creating resource. The auto incremental setting is only available for index property.
For example if we store Test\Person objects in SQL table, the id column could be defined as auto incremental.

<manifest version="3.0" name="Test\Person">
  <properties>
    <property name="id" is_id="1" auto="incremental" inheritance-="Comhon\Manifest\Property\Index"/>
  </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "id",
            "is_id": true,
            "auto": "incremental",
            "inheritance-": "Comhon\\Manifest\\Property\\Index"
        }
    ]
}

Default property value

A default value is automatically set when instanciating object. To define a default value on a property, you have to set default attribute. Default values may be defined on string, integer, index, float, percentage, boolean and dateTime.

<manifest>
    <properties>
        <property name="myDateTime" default="2016-11-13T20:04:05+01:00" inheritance-="Comhon\Manifest\Property\DateTime"/>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "myDateTime",
            "default": "2016-11-13T20:04:05+01:00",
            "inheritance-": "Comhon\\Manifest\\Property\\DateTime"
        }
    ]
}

Required property

We can define a property as required by adding restriction is_required. A required value has to be set. Even if a property is required, it can be set as null, so if you want a required not null value, you have to define is_required AND not_null restriction.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String" is_required="1"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "is_required": true
        }
    ]
}

Dependencies

A property may depends on another one (other several). In other words, a property may be set only if another is set to. To define this behaviour you have to set depends node.

<manifest>
    <properties>
        <property name="first_property" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="second_property" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="third_property" inheritance-="Comhon\Manifest\Property\String">
            <depends>
                <property>first_property</property>
                <property>second_property</property>
            </depends>
        </property>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "first_property",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
        {
            "name": "second_property",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
        {
            "name": "third_property",
            "depends": [
                "first_property",
                "second_property"
            ],
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
    ]
}

Conflicts

A conflict between two properties means that they can't be set in same time. To define conflicts you have to set conflicts node.

<manifest>
    <properties>
        <property name="first_property" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="second_property" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="third_property" inheritance-="Comhon\Manifest\Property\String"/>
        </property>
    </properties>
    <conflicts>
        <properties>
            <property>first_property</property>
            <property>second_property</property>
        </properties>
        <properties>
            <property>first_property</property>
            <property>third_property</property>
        </properties>
  </conflicts>
</manifest>
{
    "properties": [
        {
            "name": "first_property",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
        {
            "name": "second_property",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
        {
            "name": "third_property",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
    ],
    "conflicts": [
        [
            "first_property",
            "second_property"
        ],
        [
            "first_property",
            "third_property"
        ]
    ],
}

Restrictions

Some restrictions may be applied on properties or values in array. A restriction is a rule that a value must satisfy. if an array has restrictions on its values, each value must satisfy restrictions. Properties and values in array may have several restrictions.
For each restriction we will indicate on which value it may be defined and we will explain what the value must satisfy.

Enumeration

string integer index float percentage dateTime

We want to have a property gender and this property can have only 2 values : male or female. So we must define an enumeration.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="gender" inheritance-="Comhon\Manifest\Property\String">
            <enum>
                <value>male</value>
                <value>female</value>
            </enum>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "gender",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "enum": [
                "male",
                "female"
            ]
        }
    ]
}

Interval

integer index float percentage dateTime

We want to have a property age so type might be integer but there is only a reasonable range of possible values. Actually a person can't be 300 years old or -20 (negative). So we must add an interval of allowed values.
To define an interval, we use mathematic notation :

  • [a,b] means a <= value <= b
  • ]a,b[ means a < value < b
  • [a,b[ means a <= value < b
  • ]a,b] means a < value <= b
  • ]a,] means value > a
  • [,a] means value <= a
<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="age" inheritance-="Comhon\Manifest\Property\Integer" interval="[0,130]"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "age",
            "inheritance-": "Comhon\\Manifest\\Property\\Integer",
            "interval": "[0,130]"
        }
    ]
}

Pattern

string

Earlier we have defined properties firstName and middleNames with type string. But a name can only contain alphabetic characters and possibly a - (we suppose we use only latin script), so to restrict values we can define a pattern that will refer to a regular expression.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String" pattern="name"/>
        <property name="middleNames" inheritance-="Comhon\Manifest\Property\Array">
            <values name="middleName" pattern="name" inheritance-="Comhon\Manifest\Value\String"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "pattern": "name"
        },
        {
            "name": "middleNames",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "middleName",
                "inheritance-": "Comhon\\Manifest\\Value\\String",
                "pattern": "name"
            }
        }
    ]
}

At this point we have specified the pattern but we don't have defined the regular expression.
All regular expressions that you want to define must be regrouped in a unique json file. So regular expressions file content should at least look like this :

{
    "name": "/^[a-zA-Z0-9_-]*$/"
}

The regular expression must be compatible for function preg_match.

You can register your regex file where you want on your system, you just have to reference it in config file (already seen in Configuration page).

Regular Expression

string

Regular expression is the same restriction than Pattern but instead of put a name that refer to a defined regular expression in json file, the regular expression is directly defined in manifest with regex attribute.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String" regex="/^[a-zA-Z0-9_-]*$/"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "regex": "/^[a-zA-Z0-9_-]*$/"
        }
    ]
}

The regular expression must be compatible for function preg_match.

Length

string

We can define a range for string length by adding restriction length. Length follow same syntax than interval. If you want an exact length, it may look like [x,x]

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="name" inheritance-="Comhon\Manifest\Property\String" length="[2,20]"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "name",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "length": "[2,20]"
        }
    ]
}

Size

array

We can define a range for array size by adding restriction size. Size follow same syntax than interval. If you want an exact size, it may look like [x,x]

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="middleNames" inheritance-="Comhon\Manifest\Property\Array" size="[0,3]">
            <values name="middleName" inheritance-="Comhon\Manifest\Value\String" length="[2,20]"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "middleNames",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "middleName",
                "inheritance-": "Comhon\\Manifest\\Value\\String",
                "length": "[2,20]"
            },
            "size": "[0,3]"
        }
    ]
}

Not null

all

We can define properties and array values as not null by adding restriction not_null on property to prevent to set a null value.

<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String" not_null="1"/>
        <property name="middleNames" inheritance-="Comhon\Manifest\Property\Array" not_null="1">
            <values name="middleName" inheritance-="Comhon\Manifest\Value\String" not_null="1"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "not_null": true
        },
        {
            "name": "middleNames",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "middleName",
                "inheritance-": "Comhon\\Manifest\\Value\\String",
                "not_null": true
            },
            "not_null": true
        }
    ]
}

Not empty

string array

We can define properties and array values as not empty by adding restriction not_empty on :

  • string : to prevent to set an empty string ('').
  • array : to prevent to set an empty array ([]).
<manifest version="3.0" name="Test\Person">
    <properties>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String" not_empty="1"/>
        <property name="middleNames" inheritance-="Comhon\Manifest\Property\Array" not_empty="1">
            <values name="middleName" inheritance-="Comhon\Manifest\Value\String" not_empty="1"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "properties": [
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "not_empty": true
        },
        {
            "name": "middleNames",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "middleName",
                "inheritance-": "Comhon\\Manifest\\Value\\String",
                "not_empty": true
            },
            "not_empty": true
        }
    ]
}

Model name

string

We can define restriction is_model_name. This restriction may be defined if property value is a model name. model existence will be checked automatically.

<manifest>
    <properties>
        <property name="my_value" inheritance-="Comhon\Manifest\Property\String" is_model_name="1"/>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "my_value",
            "inheritance-": "Comhon\\Manifest\\Property\\String",
            "is_model_name": true
        }
    ]
}

Local manifest

We want to add a property tattoos. A tattoo is not a simple thing, we must define a model to define it. But where define this model ? In Another Manifest file ? no because a tattoo exists only on Person body (on domestic animal too but to simply we ignore it). So we define a local manifest inside Person manifest. By the way we could define another manifest file, but it's more efficient and more understandable to define a local manifest in this case.

A local manifest follow exactly the same structure as a manifest except that it can't contain its own local manifests. Local manifests are defined in types node.

<manifest version="3.0" name="Test\Person">
    <types>
        <type name="Tattoo">
            <properties>
                <property name="type" inheritance-="Comhon\Manifest\Property\String"/>
                <property name="location" inheritance-="Comhon\Manifest\Property\String"/>
                <property name="tattooArtist" is_foreign="1" model="\Test\Person" inheritance-="Comhon\Manifest\Property\Object"/>
            </properties>
	</type>
        <!-- a local property type can contain another one -->
        <type name="Example">
            <properties>
                <property name="tattoo" model="Tattoo" inheritance-="Comhon\Manifest\Property\Object"/>
                <property name="a_name" inheritance-="Comhon\Manifest\Property\String"/>
            </properties>
        </type>
    </types>
    <properties>
        <property name="tattoos" inheritance-="Comhon\Manifest\Property\Array">
            <values name="tattoo" model="Tattoo" inheritance-="Comhon\Manifest\Value\Object"/>
        </property>
        <property name="example" model="Example" inheritance-="Comhon\Manifest\Property\Object"/>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "types": [
        {
            "name": "Tattoo",
            "properties": [
                {
                    "name": "type",
                    "inheritance-": "Comhon\\Manifest\\Property\\String"
                },
                {
                    "name": "location",
                    "inheritance-": "Comhon\\Manifest\\Property\\String"
                },
                {
                    "name": "tattooArtist",
                    "model": "\\Test\\Person",
                    "is_foreign": true,
                    "inheritance-": "Comhon\\Manifest\\Property\\Object"
                }
            ]
        }
    ],
    "properties": [
        {
            "name": "tattoos",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "tattoo",
                "model": "Tattoo",
                "inheritance-": "Comhon\\Manifest\\Value\\Object"
            }
        }
    ]
}

As you can see in xml example, a local manifest can contain model defined in another local manifest.

Use local manifests if they are not too complex and if they are often used. Otherwise It's preferable to define other manifest files, it avoid to have too complex manifests.

Inheritance

A model can extends another one. Multiple inheritance is managed so model may extends several models. All properties of parent model(s) are added to inherited model. Inherited model can't redefine an existing property in parent model.

If you don't specify a parent model, your model will automatically extends from the "root" model Comhon\Root. It is a special model that doesn't have properties, it permit to have a unique parent model for all defined models.

Before we have defined a property gender with an enumeration, but another way to do is to define two new manifests Test\Man and Test\Woman that extends Test\Person.

Test\Woman manifest may look like :

<manifest version="3.0" name="Test\Person\Woman">
    <extends>
        <type>\Test\Person</type>
    </extends>
    <properties>
        <property name="pregnant" inheritance-="Comhon\Manifest\Property\Boolean">
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person\\Woman",
    "extends": ["\\Test\\Person"],
    "properties": [
        {
            "name": "pregnant",
            "inheritance-": "Comhon\\Manifest\\Property\\Boolean"
        }
    ]
}

Before we have defined a property tattoos but we can add a property piercings for example, and those two property are very similar so we can inherit models tattoo and piercing from bodyArt.

<manifest version="3.0" name="Test\Person">
    <types>
        <type name="BodyArt">
            <properties>
                <property name="type" inheritance-="Comhon\Manifest\Property\String"/>
                <property name="location" inheritance-="Comhon\Manifest\Property\String"/>
            </properties>
        </type>
        <type name="Tattoo">
            <extends>
                <type>BodyArt</type>
            </extends>
            <properties>
                <property name="tattooArtist" model="\Test\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
            </properties>
        </type>
        <type name="Piercing">
            <extends>
                <type>BodyArt</type>
            </extends>
            <properties>
                <property name="piercer" model="\Test\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
            </properties>
        </type>
    </types>
    <properties/>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "types": [
        {
            "name": "BodyArt",
            "properties": [
                {
                    "name": "type",
                    "inheritance-": "Comhon\\Manifest\\Property\\String"
                },
                {
                    "name": "location",
                    "inheritance-": "Comhon\\Manifest\\Property\\String"
                }
            ]
        },
        {
            "name": "Tattoo",
            "extends": ["BodyArt"],
            "properties": [
                {
                    "name": "tattooArtist",
                    "model": "\\Test\\Person",
                    "is_foreign": true,
                    "inheritance-": "Comhon\\Manifest\\Property\\Object"
                }
            ]
        },
        {
            "name": "Piercing",
            "extends": ["BodyArt"],
            "properties": [
                {
                    "name": "piercer",
                    "model": "\\Test\\Person",
                    "is_foreign": true,
                    "inheritance-": "Comhon\\Manifest\\Property\\Object"
                }
            ]
        }
    ],
    "properties": []
}

for multiple inheritance we just have to indicate several model names.

<manifest>
    <extends>
        <type>\Test\FirstParent</type>
        <type>\Test\SecondParent</type>
    </extends>
    <properties/>
</manifest>
{
    "extends": ["\\Test\\FirstParent","\\Test\\SecondParent"],
    "properties": []
}

Abstract model

You can define model as abstract. Objects with abstract model may be instanciated but can't be :

  • flagged as loaded
  • exported/serialized
  • imported/deserialized
<manifest version="3.0" name="Test\Person" is_abstract="1">
    <properties/>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "is_abstract": true,
    "properties": []
}

Share id

Here we will just define how to set a share id. For more informations about what is share id, take a look at Share id chapter.

There are two way to define a share id :

  • With share_parent_id attribute. If model inherit from another one, it will share id with parent model. If a model inherit from several models (multiple inheritance), it will share id with the first parent model. Models may have same share id in cascade.

For example following manifest example will share it id with Test\FirstParent model

<manifest share_parent_id="1">
    <extends>
        <type>\Test\FirstParent</type>
        <type>\Test\SecondParent</type>
    </extends>
    <properties/>
</manifest>
{
    "share_parent_id": true,
    "extends": ["\\Test\\FirstParent","\\Test\\SecondParent"],
    "properties": []
}
  • With shared_id attribute. You can define directly the model that will share id with current defined model. You can't specify any model, current model must inherit from specified model.
<manifest shared_id="\Test\GrandParent">
    <extends>
        <type>\Test\Parent</type>
    </extends>
    <properties/>
</manifest>
{
    "shared_id": "\\Test\\GrandParent",
    "extends": ["\\Test\\Parent"],
    "properties": []
}

Isolated value

Here we will just define how to set an isolated value. For more informations about what is an isolated value, take a look at Isolated value chapter.
To defined a property or an array value as isolated, you have to set is_isolated attribute.

<manifest>
    <properties>
        <property name="my_obj" model="\Test\Object"  is_isolated="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="my_objs" inheritance-="Comhon\Manifest\Property\Array">
            <values name="my_obj_bis" model="\Test\ObjectBis" is_isolated="1" inheritance-="Comhon\Manifest\Value\Object"/>
        </property>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "my_obj",
            "model": "\\Test\\Object",
            "is_isolated": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        },
        {
            "name": "my_objs",
            "inheritance-": "Comhon\\Manifest\\Property\\Array",
            "values": {
                "name": "my_obj_bis",
                "model": "\\Test\\ObjectBis",
                "is_isolated": true,
                "inheritance-": "Comhon\\Manifest\\Value\\Object"
            }
        }
    ]
}

Associate a class object

if you want to associate a class to your manifest you can define it in the attribute object. The class must contain namespace.

<manifest object="\Fully\Qualified\Name\Class">
    <properties/>
</manifest>
{
    "object": "\\Fully\\Qualified\\Name\\Class",
    "properties": []
}

Take a look at Getting started page to know how to define a class object and how to instanciate it.

Main

The is_main attribute permit to identify model as main model. Objects with main model may be stored in Main Object Collection.

<manifest is_main="1">
    <properties/>
</manifest>
{
    "is_main": true,
    "properties": []
}

Namespace

All models described with manifests have an associated namespace. All namespace are prefixed by a name that correspond to a specific autoloading (we will see why in next chapter). For example all Comhon! models are prefixed by Comhon\. Here are some examples :

  • the Fully qualified name of model Config is Comhon\Config
  • the Fully qualified name of model SqlDatabase is Comhon\SqlDatabase

In a manifest you can refer to a model by using fully qualified name of a model or use name relative to current manifest namespace. A fully qualified name begin with a \ and relative name don't. Local manifests are concerned by namespace, they must be defined without namespace but you have to refer to them using fully qualified name or relative name.

For example we suppose that model Person namespace is prefixed by Test and it's fully qualified name is Test\Person. The fully qualified name of model Tattoo might be Test\Person\Tattoo and we could refer to it in manifest Test\Person by using fully qualified name \Test\Person\Tattoo or relative name Tattoo.

<type name="Tattoo">
    <extends>
        <type>\Test\Person\BodyArt</type>
    </extends>
    <!-- ... -->
</type>
<!-- ... -->
<property name="tattoo" model="\Test\Person\Tattoo" inheritance-="Comhon\Manifest\Property\Object"/>

is equivalent to

<type name="Tattoo">
    <extends>
        <type>BodyArt</type>
    </extends>
    <!-- ... -->
</type>
<!-- ... -->
<property name="tattoo" model="Tattoo" inheritance-="Comhon\Manifest\Property\Object"/>

In PHP sources you have to always use fully qualified name and you have to omit first backslash :

$personModel = ModelManager::getInstance()->getInstanceModel('Test\Person');
$tattooModel = ModelManager::getInstance()->getInstanceModel('Test\Person\Tattoo');

$person = new ComhonObject('Test\Person');
$tattoo = new ComhonObject('Test\Person\Tattoo');

Autoloading

Comhon! use autoloading to find and load manifests (like PHP does to find classes). Actually manifests are loaded only if needed. To do so you have to define your autoloading in Configuration file.

Examples

We want to have two different directories to store our manifests. We may have a config file that look like :

{
  "autoload": {
    "manifest":{
      "Test":"../relative/path/to/manifests/test",
      "Tutorial":"/absolute/path/to/manifests/tutorial"
    }
  }
}
  • All manifest described in directory ../relative/path/to/manifests/test will have namespace prefixed by Test;
  • All manifest described in directory /absolute/path/to/manifests/tutorial will have namespace prefixed by Tutorial;

In file system each manifest must respect following rules :

  • manifest is contained in directory and the directory name must correspond to the model name
  • manifest file must be named manifest.json or manifest.xml (depends on manifest format defined in Configuration file)

Examples

  • We want to add a manifest to describe model Test\Person, it must be saved at:
../relative/path/to/manifests/test/Person/manifest.json
or
../relative/path/to/manifests/test/Person/manifest.xml
  • We want to add a manifest to describe model Tutorial\Instrument\Guitare, it must be saved at :
/absolute/path/to/manifests/tutorial/Instrument/Guitare/manifest.json
or
/absolute/path/to/manifests/tutorial/Instrument/Guitare/manifest.xml

Manifest Person example

<manifest version="3.0" name="Test\Person" object="\Comhon\Object\Person">
    <types>
        <type name="BodyArt">
            <properties>
                <property name="type" inheritance-="Comhon\Manifest\Property\String"/>
                <property name="location" inheritance-="Comhon\Manifest\Property\String"/>
            </properties>
        </type>
        <type name="Tattoo">
            <extends>
                <type>BodyArt</type>
            </extends>
            <properties>
                <property name="tattooArtist" model="\Test\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
            </properties>
        </type>
        <type name="Piercing">
            <extends>
                <type>BodyArt</type>
            </extends>
            <properties>
                <property name="piercer" model="\Test\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
            </properties>
        </type>
    </types>
    <properties>
        <property name="id" is_id="1" auto="incremental" inheritance-="Comhon\Manifest\Property\Index"/>
        <property name="firstName" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="lastName" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="birthDate" inheritance-="Comhon\Manifest\Property\DateTime"/>
        <property name="birthPlace" model="\Test\Place" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="bestFriend" model="\Test\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="father" model="\Test\Person\Man" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="mother" model="\Test\Person\Woman" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="children" inheritance-="Comhon\Manifest\Property\Aggregation">
            <values model="\Test\Person" name="child"/>
            <aggregations>
                <property>mother</property>
                <property>father</property>
            </aggregations>
        </property>
        <property name="homes" inheritance-="Comhon\Manifest\Property\Aggregation">
            <values name="home" model="\Test\House"/>
            <aggregations>
                <property>owner</property>
            </aggregations>
        </property>
        <property name="bodyArts" inheritance-="Comhon\Manifest\Property\Array">
            <values name="bodyArt" model="BodyArt" inheritance-="Comhon\Manifest\Value\Object"/>
        </property>
    </properties>
</manifest>
{
    "version": "3.0",
    "name": "Test\\Person",
    "types": [
        {
            "name": "BodyArt",
            "properties": [
                {
                    "name": "type",
                    "inheritance-": "Comhon\\Manifest\\Property\\String"
                },
                {
                    "name": "location",
                    "inheritance-": "Comhon\\Manifest\\Property\\String"
                }
            ]
        },
        {
            "name": "Tattoo",
            "extends": [
                "BodyArt"
            ],
            "properties": [
                {
                    "name": "tattooArtist",
                    "model": "\\Test\\Person",
                    "is_foreign": true,
                    "inheritance-": "Comhon\\Manifest\\Property\\Object"
                }
            ]
        },
        {
            "name": "Piercing",
            "extends": [
                "BodyArt"
            ],
            "properties": [
                {
                    "name": "piercer",
                    "model": "\\Test\\Person",
                    "is_foreign": true,
                    "inheritance-": "Comhon\\Manifest\\Property\\Object"
                }
            ]
        }
    ],
    "properties": [
        {
            "name": "id",
            "is_id": true,
            "auto": "incremental",
            "inheritance-": "Comhon\\Manifest\\Property\\Index"
        },
        {
            "name": "firstName",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
        {
            "name": "lastName",
            "inheritance-": "Comhon\\Manifest\\Property\\String"
        },
        {
            "name": "birthDate",
            "inheritance-": "Comhon\\Manifest\\Property\\DateTime"
        },
        {
            "name": "birthPlace",
            "model": "\\Test\\Place",
            "is_foreign": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        },
        {
            "name": "bestFriend",
            "model": "\\Test\\Person",
            "is_foreign": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        },
        {
            "name": "father",
            "model": "\\Test\\Person\\Man",
            "is_foreign": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        },
        {
            "name": "mother",
            "model": "\\Test\\Person\\Woman",
            "is_foreign": true,
            "inheritance-": "Comhon\\Manifest\\Property\\Object"
        },
        {
            "name": "children",
            "values": {
                "name": "child",
                "model": "\\Test\\Person"
            },
            "aggregations": [
                "mother",
                "father"
            ],
            "inheritance-": "Comhon\\Manifest\\Property\\Aggregation"
        },
        {
            "name": "homes",
            "values": {
                "name": "home",
                "model": "\\Test\\House"
            },
            "aggregations": [
                "owner"
            ],
            "inheritance-": "Comhon\\Manifest\\Property\\Aggregation"
        },
        {
            "name": "bodyArts",
            "values": {
                "name": "bodyArt",
                "model": "BodyArt",
                "inheritance-": "Comhon\\Manifest\\Value\\Object"
            },
            "inheritance-": "Comhon\\Manifest\\Property\\Array"
        }
    ]
}
name: Test\Person
version: '3.0'
types:
    -
        name: BodyArt
        properties:
            -
                name: type
                inheritance-: Comhon\Manifest\Property\String
            -
                name: location
                inheritance-: Comhon\Manifest\Property\String
    -
        name: Tattoo
        extends:
            - BodyArt
        properties:
            -
                name: tattooArtist
                model: \Test\Person
                is_foreign: true
                inheritance-: Comhon\Manifest\Property\Object
    -
        name: Piercing
        extends:
            - BodyArt
        properties:
            -
                name: piercer
                model: \Test\Person
                is_foreign: true
                inheritance-: Comhon\Manifest\Property\Object
properties:
    -
        name: id
        is_id: true
        auto: incremental
        inheritance-: Comhon\Manifest\Property\Index
    -
        name: firstName
        inheritance-: Comhon\Manifest\Property\String
    -
        name: lastName
        inheritance-: Comhon\Manifest\Property\String
    -
        name: birthDate
        inheritance-: Comhon\Manifest\Property\DateTime
    -
        name: birthPlace
        model: \Test\Place
        is_foreign: true
        inheritance-: Comhon\Manifest\Property\Object
    -
        name: bestFriend
        model: \Test\Person
        is_foreign: true
        inheritance-: Comhon\Manifest\Property\Object
    -
        name: father
        model: \Test\Person\Man
        is_foreign: true
        inheritance-: Comhon\Manifest\Property\Object
    -
        name: mother
        model: \Test\Person\Woman
        is_foreign: true
        inheritance-: Comhon\Manifest\Property\Object
    -
        name: children
        values:
            name: child
            model: \Test\Person
        aggregations:
            - mother
            - father
        inheritance-: Comhon\Manifest\Property\Aggregation
    -
        name: homes
        values:
            name: home
            model: \Test\House
        aggregations:
            - owner
        inheritance-: Comhon\Manifest\Property\Aggregation
    -
        name: bodyArts
        values:
            name: bodyArt
            model: BodyArt
            inheritance-: Comhon\Manifest\Value\Object
        inheritance-: Comhon\Manifest\Property\Array

Clone this wiki locally