Skip to content
comhon-project edited this page Aug 6, 2017 · 57 revisions

Table of Contents

  1. Manifest list
  2. Manifest description
    1. Properties
      1. Basic property
      2. Id property
      3. Foreign property
      4. Array property
      5. Restricted property
        1. Enumeration
        2. Interval
        3. Pattern
    2. Local property type
    3. Inheritance
    4. Associate a class object
    5. Namespace
  3. Manifest Person example

Manifest list

The list of all your manifests must be referenced in an XML or JSON file. The path to this file must be defined in the file config.json with the key manifestList (see Installation page for more informations).
You have to specify the manifest list version to determine witch parser will be used to parse the document. There is currently only one version allowed 2.0.

If you decide to define your manifest list in XML format, your file must have "xml" extention and content must look like :

<manifests version="2.0">
    <person>relative/path/to/person/manifest.xml</person>
    <house>relative/path/to/house/manifest.xml</house>
    <town>relative/path/to/town/manifest.xml</town>
</manifests>

If you decide to define your manifest list in JSON format, your file must have "json" extention and content must look like :

{
    "version" : "2.0",
    "list" : {
        "person" : "relative/path/to/person/manifest.json",
        "house"  : "relative/path/to/house/manifest.json",
        "town"   : "relative/path/to/town/manifest.json"
    }
}

As you can see the list permit to associate a name to a manifest path. Each name is unique and each manifest path must have "xml" or "json" extention. Finaly the manifest path must be relative to the folder that contain manifest list file.

Manifest description

A Manifest permit to describe a concept by listing its properties. Manifests can be defined in XML or JSON format. for each example we will illustrate XML and JSON format.
You have to specify the manifest version to determine witch parser will be used to parse the document. There is currently only one version allowed 2.0.

<manifest version="2.0">
    <properties>
        ...
    </properties>
</manifest>
{
    "version": "2.0",
    "properties": []
}

for the following explanations we will build a manifest Person like example.

Properties

Basic property

A property has a name and a type

<manifest>
    <properties>
        <property type="string" name="firstName"/>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "firstName",
            "type": "string"
        }
    ]
}

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>
    <properties>
        <property type="string" name="id" is_id="1"/>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "id",
            "type": "string",
            "is_id": true
        }
    ]
}

Foreign property

A Foreign property is a property that contain the key is_foreign, it refers another Object that has an existence elsewhere. For example, model Person can have a foreign property mother. A random person 'John' has a mother 'Jane' and 'Jane' can exist without 'John'.

<manifest>
    <properties>
        <property type="string" name="\mother" is_foreign="1"/>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "mother",
            "type": "\\person",
            "is_foreign": true
        }
    ]
}

(we will explain later why there is backslash in type value)

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>
    <properties>
        <property type="array" name="middleNames">
            <values type="string" name="middleName"/>
        </property>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "middleNames",
            "type": "array",
            "values": {
                "type": "string",
                "name": "middleName"
            }
        }
    ]
}

Now we want to have a property children, and a child is a person that can exists elsewhere so we can build a foreign property array.

<manifest>
    <properties>
        <property type="array" name="children" is_foreign="true">
            <values type="\person" name="child"/>
        </property>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "children",
            "type": "array",
            "values": {
                "type": "\\person",
                "name": "child"
            },
            "is_foreign": true
        }
    ]
}

Restricted property

A restricted property is a property with a simple type (integer, string ....) but with a restricted range of allowed values

Enumeration

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

<manifest>
    <properties>
        <property type="string" name="sex">
            <enum>
                <value>male</value>
                <value>female</value>
            </enum>
        </property>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "sex",
            "type": "string",
            "enum": [
                "male",
                "female"
            ]
        }
    ]
}

Enumerations are allowed on integer, float and string

Interval

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>
    <properties>
        <property type="integer" name="age" interval="[0,130]"/>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "age",
            "type": "integer",
            "interval": "[0,130]"
        }
    ]
}

Intervals are allowed on integer, float and ComhonDateTime

Pattern

Earlier we have defined a 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 range of values we can define a pattern that will refer to a regular expression.

<manifest>
    <properties>
        <property type="string" name="firstName" pattern="name"/>
        <property type="array" name="middleNames">
            <values type="string" name="middleName" pattern="name"/>
        </property>
    </properties>
</manifest>
{
    "properties": [
        {
            "name": "firstName",
            "type": "string",
            "pattern": "name"
        },
        {
            "name": "middleNames",
            "type": "array",
            "values": {
                "type": "string",
                "name": "middleName",
                "pattern": "name"
            }
        }
    ]
}

At this point we have defined 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 file where you want on your system, you just have to reference it in config file (already seen in installation page).
the path to your file must be absolute in the key regexList. File content should look like :

{
  "manifestList": "/absolute/path/to/directory/where/is/saved/file/manifestList.xml",
  "serializationList": "/absolute/path/to/directory/where/is/saved/file/serializationList.xml",
  "regexList": "/absolute/path/to/regex/file.json"
}

Local property type

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

<manifest>
    <types>
        <type name="tatoo">
            <properties>
                <property type="string" name="type"/>
                <property type="string" name="location"/>
                <property type="\person" name="tatooArtist" is_foreign="1"/>
            </properties>
	</type>
        <!-- a local property type can contain another one -->
        <type name="example">
            <properties>
                <property type="tatoo" name="tatoo"/>
                <property type="string" name="a_name"/>
            </properties>
        </type>
    </types>

    <properties>
        <property type="array" name="tatoos">
            <values type="tatoo" name="tatoo"/>
        </property>
        <property type="example">example</property>
    </properties>
</manifest>
{
    "types": [
        {
            "name": "tatoo",
            "properties": [
                {
                    "name": "type",
                    "type": "string"
                },
                {
                    "name": "location",
                    "type": "string"
                },
                {
                    "name": "tatooArtist",
                    "type": "\\person",
                    "is_foreign": true
                }
            ]
        }
    ],
    "properties": [
        {
            "name": "tatoos",
            "type": "array",
            "values": {
                "type": "tatoo",
                "name": "tatoo"
            }
        }
    ]
}

If you have a large number of complex local models and they are not always used, you can define them in others manifests files.

advantages :

  • simplify the current manifest
  • load local model only if needed (saving time when load current manifest)
<manifest>
    <manifests>
        <localThing>relative/path/to/local/manifest.xml</localThing>
        <localAnotherThing>relative/path/to/another/local/manifest.xml</localAnotherThing>
    </manifests>

    <properties>
        <property type="localThing" name="thing"/>
        <property type="localAnotherThing" name="anotherThing"/>
    </properties>
</manifest>
{
    "manifests": {
        "localThing": "relative/path/to/local/manifest.xml",
        "localAnotherThing": "relative/path/to/another/local/manifest.xml"
    },
    "properties": [
        {
            "name": "thing",
            "type": "localThing"
        },
        {
            "name": "anotherThing",
            "type": "localAnotherThing"
        }
    ]
}

Inheritance

A model can extends another one. All properties of parent model are added to inherited model. Inherited model can overrider an existing property in parent model. Inheritance can be defined on manifests and on local types.

Before we have defined a property sex with an enumeration, but another way to do is to define a model Man and Woman that extends Person.

<manifest extends="\person">
    <properties>
        <!-- some properties specific to woman -->
    </properties>
</manifest>
{
    "extends": "\\person",
    "properties": []
}

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>
    <types>
        <type name="bodyArt">
            <properties>
                <property type="string" name="type"/>
                <property type="string" name="location"/>
            </properties>
        </type>
        <type name="tattoo" extends="bodyArt">
            <properties>
                <property is_foreign="1" type="\person" name="tattooArtist"/>
            </properties>
        </type>
        <type name="piercing" extends="bodyArt">
            <properties>
                <property is_foreign="1" type="\person" name="piercer"/>
            </properties>
        </type>
    </types>
    <properties/>
</manifest>
{
        "types": [
        {
            "name": "bodyArt",
            "properties": [
                {
                    "name": "type",
                    "type": "string"
                },
                {
                    "name": "location",
                    "type": "string"
                }
            ]
        },
        {
            "name": "tattoo",
            "extends": "bodyArt",
            "properties": [
                {
                    "name": "tattooArtist",
                    "type": "\\person",
                    "is_foreign": true
                }
            ]
        },
        {
            "name": "piercing",
            "extends": "bodyArt",
            "properties": [
                {
                    "name": "piercer",
                    "type": "\\person",
                    "is_foreign": true
                }
            ]
        }
    ],
    "properties": []
}

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="Class\With\Name\Space\A_Class">
    <properties/>
</manifest>
{
    "object": "Class\\With\\Name\\Space\\A_Class",
    "properties": []
}

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

Namespace

All models described with manifests and local types have an associated namespace. You have probably seen \person in previous examples, the backslash means that we have a fully qualified name. If there is no backslash that means it is an unqualified name and the current namespace is applied. There is an exception, simple models doesn't have backslash and are not concerned by namespace (see list of simple models).

We have previously defined the local type tattoo in manifest of person so the fully qualified name of tattoo is \person\tattoo. if tattoo was defined in an external manifest and had its own local types, these models should have a fully qualified name like \person\tattoo\a_name

In php sources you have to omit first backslash :

$personModel = ModelManager::getInstance()->getInstanceModel('person');
$tattooModel = ModelManager::getInstance()->getInstanceModel('person\tattoo');

Manifest Person example

<manifest version="2.0" object="Comhon\Object\Person">
    <types>
        <type name="bodyArt">
            <properties>
                <property type="string" name="type"/>
                <property type="string" name="location"/>
            </properties>
        </type>
        <type name="tattoo" extends="bodyArt">
            <properties>
                <property is_foreign="1" type="\person" name="tattooArtist"/>
            </properties>
        </type>
        <type name="piercing" extends="bodyArt">
            <properties>
                <property is_foreign="1" type="\person" name="piercer"/>
            </properties>
        </type>
    </types>
    <properties>
        <property type="integer" is_id="1" name="id"/>
        <property type="string" name="firstName"/>
        <property type="string" name="lastName"/>
        <property type="dateTime" name="birthDate"/>
        <property is_foreign="1" type="\place" name="birthPlace"/>
        <property is_foreign="1" type="\person" name="bestFriend"/>
        <property is_foreign="1" type="\man" name="father"/>
        <property is_foreign="1" type="\woman" name="mother"/>
        <property is_foreign="1" type="array" name="children">
            <values type="\person" name="child"/>
        </property>
        <property is_foreign="1" type="array" name="homes">
            <values type="\home" name="home"/>
        </property>
        <!--<property is_foreign="1" type="array" name="realEstateProperties">
            <values type="\home"/>
        </property>-->
    </properties>
</manifest>
{
    "version": "2.0",
    "object": "Comhon\\Object\\Person",
    "types": [
        {
            "name": "bodyArt",
            "properties": [
                {
                    "name": "type",
                    "type": "string"
                },
                {
                    "name": "location",
                    "type": "string"
                }
            ]
        },
        {
            "name": "tattoo",
            "extends": "bodyArt",
            "properties": [
                {
                    "name": "tattooArtist",
                    "type": "\\person",
                    "is_foreign": true
                }
            ]
        },
        {
            "name": "piercing",
            "extends": "bodyArt",
            "properties": [
                {
                    "name": "piercer",
                    "type": "\\person",
                    "is_foreign": true
                }
            ]
        }
    ],
    "properties": [
        {
            "name": "id",
            "type": "integer",
            "is_id": true
        },
        {
            "name": "firstName",
            "type": "string"
        },
        {
            "name": "lastName",
            "type": "string"
        },
        {
            "name": "birthDate",
            "type": "dateTime"
        },
        {
            "name": "birthPlace",
            "type": "\\place",
            "is_foreign": true
        },
        {
            "name": "bestFriend",
            "type": "\\person",
            "is_foreign": true
        },
        {
            "name": "father",
            "type": "\\man",
            "is_foreign": true
        },
        {
            "name": "mother",
            "type": "\\woman",
            "is_foreign": true
        },
        {
            "name": "children",
            "type": "array",
            "values": {
                "type": "\\person",
                "name": "child"
            },
            "is_foreign": true
        },
        {
            "name": "homes",
            "type": "array",
            "values": {
                "type": "\\home",
                "name": "home"
            },
            "is_foreign": true
        }
    ]
}

Clone this wiki locally