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

Table of contents

  1. Preamble
  2. Dataset
  3. Simple requester
  4. Complex requester
    1. Intermediate request format
    2. Advanced request format
    3. Order, offset and limit
    4. Returned properties
    5. Count

Preamble

Requester permit to retrieve any comhon object with a serialization set. It allow to build complex requests in unique Comhon! request format and it will transform requests in language understandable by your "serialization system" (for example SQL database).

First, the request must be built, and second, it must be executed. The execution will return a ComhonObject (for simple requests) or a ComhonArray (for complex requests).
Requests might be executed in public or private context. In public context, some settings might be not available to protect some private data or to prevent requests too complex with too long execution time.

If any error appears, for example a malformed request, a ComhonException will be thrown (All error codes are listed in class Comhon\Exception\ConstantException).

Dataset

To have a better comprehension we will define some manifest and serialized object

Person

Manifest

<root name="Sample\Person" is_abstract="1" version="3.0">
    <properties>
        <property name="id" is_id="1" auto="incremental" inheritance-="Comhon\Manifest\Property\Index"/>
        <property name="firstName" not_null="1" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="lastName" not_null="1" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="birthDate" not_null="1" inheritance-="Comhon\Manifest\Property\DateTime"/>
        <property name="birthPlace" model="\Sample\Place" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="father" model="\Sample\Person\Man" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="mother" model="\Sample\Person\Woman" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
        <property name="children" inheritance-="Comhon\Manifest\Property\Aggregation">
            <values name="child" model="\Sample\Person"/>
            <aggregations>
                <aggregation>mother</aggregation>
                <aggregation>father</aggregation>
            </aggregations>
        </property>
        <property name="houses" inheritance-="Comhon\Manifest\Property\Aggregation">
            <values name="house" model="\Sample\House"/>
            <aggregations>
                <aggregation>owner</aggregation>
            </aggregations>
        </property>
    </properties>
</root>

Serialization

<root name="Sample\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="birthPlace" serialization_name="birth_place_id"/>
        <property property_name="father" serialization_name="father_id"/>
        <property property_name="mother" serialization_name="mother_id"/>
    </properties>
</root>

Serialized object

id first_name last_name birth_date birth_place_id father_id mother_id gender
1 john doe 1972-11-13 20:04:05+00 1 Sample\Person\Man
2 jane doe 1970-01-13 20:04:05+00 2 Sample\Person\Woman
3 marie doe 1995-11-10 20:04:05+00 3 1 2 Sample\Person\Woman
4 philippe doe 1998-05-01 20:04:05+00 3 1 2 Sample\Person\Man
5 emilie doe 1994-06-23 20:02:59+00 2 1 Sample\Person\Woman
6 walter doe 2016-09-21 20:02:59+00 2 5 Sample\Person\Man
7 jesse doe 2018-10-04 20:02:59+00 2 5 Sample\Person\Man

Woman

Manifest

<root name="Sample\Person\Woman" version="3.0">
  <extends>
    <type>\Sample\Person</type>
  </extends>
</root>

Serialization

<root name="Sample\Person\Woman" version="3.0">
    <inheritance_values>
        <model>Sample\Person\Woman</model>
    </inheritance_values>
</root>

Serialized object

See Sample\Person serialized object.

Man

Manifest

<root name="Sample\Person\Man" version="3.0">
  <extends>
    <type>\Sample\Person</type>
  </extends>
</root>

Serialization

<root name="Sample\Person\Man" version="3.0">
    <inheritance_values>
        <model>Sample\Person\Man</model>
    </inheritance_values>
</root>

Serialized object

See Sample\Person serialized object.

House

Manifest

<root name="Sample\House" version="3.0">
    <properties>
        <property name="id" is_id="1" auto="incremental" inheritance-="Comhon\Manifest\Property\Index"/>
        <property name="surface" inheritance-="Comhon\Manifest\Property\Float"/>
        <property name="garden" inheritance-="Comhon\Manifest\Property\Boolean"/>
        <property name="owner" model="\Sample\Person" is_foreign="1" inheritance-="Comhon\Manifest\Property\Object"/>
    </properties>
</root>

Serialization

<root name="Sample\House" version="3.0">
    <serialization>
        <foreign_settings id="house" inheritance-="Comhon\SqlTable"/>
    </serialization>
    <properties>
        <property property_name="owner" serialization_name="owner_id"/>
    </properties>
</root>

Serialized object

id surface garden owner_id
1 110 false 1
2 130 true 2
3 120 true 2

Place

Manifest

<root name="Sample\Place" version="3.0">
    <properties>
        <property name="id" is_id="1" auto="incremental" inheritance-="Comhon\Manifest\Property\Index"/>
        <property name="number" inheritance-="Comhon\Manifest\Property\Integer"/>
        <property name="type" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="name" inheritance-="Comhon\Manifest\Property\String"/>
        <property name="town" inheritance-="Comhon\Manifest\Property\String"/>
    </properties>
</root>

Serialization

<root name="Sample\Place" version="3.0">
    <serialization>
        <foreign_settings id="place" inheritance-="Comhon\SqlTable"/>
    </serialization>
</root>

Serialized object

id number type name town
1 16 street main street New York
2 3 street second street New York
3 10 avenue Jean Moulin Paris

Simple requester

Simple requester permit to retrieve one object by its model name and its id. The entrypoint is Comhon\Request\SimpleRequester. It manage all types of serialization. You cannot use it if your model doesn't have id property.

$modelName = 'Sample\Person';
$id = 1;
$filterProperties = null;
$isPrivate = true;

$requester = SimpleRequester::build($modelName, $id, $filterProperties, $isPrivate);
$result = $requester->execute(); // return ComhonObject or null if not found

If your model has several id properties you must specify them in a json encoded array, and order of values must be the same as order of id properties in manifest.

$modelName = 'Sample\MyModel';
$id = '[1,"id2",456]';
$filterProperties = null;
$isPrivate = true;

$requester = SimpleRequester::build($modelName, $id, $filterProperties, $isPrivate);
$result = $request->execute(); // return ComhonObject or null if not found

Complex requester

Complex requester permit to retrieve, in same time, several objects that match with some given filters. Only objects with an SQL database serialization (Comhon\SqlTable) might be requested, and filter's models must be linked to the same SQL database.
The entrypoint to build and execute complex requests is Comhon\Request\ComplexRequester.

$requester = ComplexRequester::build($request, $isPrivate);
$result = $requester->execute(); // return ComhonArray

The first parameter might be a comhon object or an interfaced object (StdClass, array, DomNode, SimpleXMLElement). if an interfaced object is given, it will be imported in comhon object.
Model of comhon object request must be either Comhon\Request\Intermediate or Comhon\Request\Complex.

  • Requests manifests are defined here.
  • Logical filters manifests are defined here.
  • Model nodes manifests are defined here.

Intermediate request format

The intermediate request format correspond to model Comhon\Request\Intermediate.
You can see associated manifest here.

Use case 1

States

I want houses
-that have a surface supperior than 90 m“ or with a garden
-and that have an owner called marie or jane, and born in second street New York

Request

{
    "root": 1,
    "filter": 0,
    "models": [
        {
            "id": 0,
            "model": "Sample\\Person"
        },
        {
            "id": 1,
            "model": "Sample\\House"
        },
        {
            "id": 2,
            "model": "Sample\\Place"
        }
    ],
    "simple_collection": [
        {
            "id": 0,
            "elements": [
                1,
                2,
                3,
                4
            ],
            "type": "conjunction",
            "inheritance-": "Comhon\\Logic\\Simple\\Clause"
        },
        {
            "id": 1,
            "elements": [
                5,
                6
            ],
            "type": "disjunction",
            "inheritance-": "Comhon\\Logic\\Simple\\Clause"
        },
        {
            "id": 2,
            "node": 0,
            "property": "firstName",
            "operator": "IN",
            "values": ["marie","jane"],
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\Set\\String"
        },
        {
            "id": 3,
            "node": 2,
            "property": "name",
            "operator": "=",
            "value": "second street",
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\String"
        },
        {
            "id": 4,
            "node": 2,
            "property": "town",
            "operator": "=",
            "value": "New York",
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\String"
        },
        {
            "id": 5,
            "node": 1,
            "property": "surface",
            "operator": ">",
            "value": 90,
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\Numeric\\Float"
        },
        {
            "id": 6,
            "node": 1,
            "property": "garden",
            "operator": "=",
            "value": true,
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\Boolean"
        }
    ],
    "inheritance-": "Comhon\\Request\\Intermediate"
}

Result

Stringified ComhonArray :

[
    {
        "id": 2,
        "surface": 130,
        "garden": true,
        "owner": 2
    },
    {
        "id": 3,
        "surface": 120,
        "garden": true,
        "owner": 2
    }
]

Explanations

In intermediate request you don't have to specify relations between differents models, the requester will find them automatically (relations between models permit to construct SQL joins between tables).

  • Your request must have at least :
    • root : The requested objects model. It is a reference to a model node in models list.
    • models : The list of all model nodes (requested model and models filter)
  • Your request may have following filter informations :
    • filter : The filter to apply. It is a reference to a literal or a clause in simple_collection.
    • simple_collection : The list of all literals and clauses
    • having_collection : The list of all having literals and having clauses (explain in next request)
Literal

A literal represent a condition in data base request, something like WHERE (foo = 'bar').
In intermediate request, literal must have following properties :

  • id: the literal identifier
  • node: a reference to a model node in models list
  • property: the property name
  • operator: =,<>,<,>,<=,>=, IN, NOT IN
  • value or values: the filter value
  • inheritance- : the formula's model name
Clause

A clause is a group of several literals and/or sub clauses, something like WHERE ... ((foo = 'bar') AND (bar = 'foo')).

  • id: the clause identifier
  • elements: list of references to existing literals or clauses
  • type: it determine if elements in clause are linked by AND or OR
    • disjonction : OR
    • conjonction : AND
  • inheritance- : the formula's model name
Logical Form

the logical form of previous request would be : (a ∨ b) ∧ c ∧ d ∧ e

Use case 2

States

I want persons
-named Paul or john
-and which have between 2 and 6 grandchildren

Request

{
    "root": 0,
    "filter": 0,
    "models": [
        {
            "id": 0,
            "model": "Sample\\Person"
        }
    ],
    "simple_collection": [
        {
            "id": 0,
            "elements": [
                1,
                2
            ],
            "type": "conjunction",
            "inheritance-": "Comhon\\Logic\\Simple\\Clause"
        },
        {
            "id": 1,
            "node": 0,
            "property": "firstName",
            "operator": "IN",
            "values": ["Paul","john"],
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\Set\\String"
        },
        {
            "id": 2,
            "node": 0,
            "queue": ["children", "children"],
            "having": 0,
            "inheritance-": "Comhon\\Logic\\Simple\\Having"
        }
    ],
    "having_collection": [
        {
            "id": 0,
            "elements": [
                1,
                2
            ],
            "type": "conjunction",
            "inheritance-": "Comhon\\Logic\\Having\\Clause"
        },
        {
            "id": 1,
            "operator": ">=",
            "value": 2,
            "inheritance-": "Comhon\\Logic\\Having\\Literal\\Count"
        },
        {
            "id": 2,
            "operator": "<=",
            "value": 6,
            "inheritance-": "Comhon\\Logic\\Having\\Literal\\Count"
        }
    ],
    "inheritance-": "Comhon\\Request\\Intermediate"
}

Result

Stringified ComhonArray :

[
    {
        "id": 1,
        "firstName": "john",
        "lastName": "doe",
        "birthPlace": 1,
        "father": null,
        "mother": null,
        "inheritance-": "Sample\\Person\\Man"
    }
]

Explanations

Now let's explain literal having. A literal having is described by manifest here.
It contains having literal or having clause. Notice the difference between "literal having" that might be find in simple_collection and "having literal" or "having clause" that might be find in having_collection.

A literal having must have :

  • id: the literal identifier
  • node: a reference to a model node in models list
  • queue: properties stack that begin from node model
  • having: a reference to a having literal or a having clause in having_collection.
  • inheritance- : the formula's model name (one possible value : Comhon\Logic\Simple\Having)
Queue

A queue permit to know on which node you want to apply your having filter. The queue is a stack of properties name that begin from node model. In previous request example we start from the root model Sample\Person and we apply having filter on children of children of first person, in other words on grandchildren.

Having clause

A having clause is like a simple clause but can only contain having literals and having clauses.

Having literal

A having literal represent a condition in data base request, something like HAVING ... COUNT(foo) = bar

There are two kind of having literal :

  • The count having literal, it must have following properties :
    • operator: =,<>,<,>,<=,>=
    • value: integer
  • The function having literals, it must have following properties :
    • function: the function to apply (SUM,AVG,MAX,MIN)
    • property: the property name
    • operator: =,<>,<,>,<=,>=
    • value: float

Limitations

  • Imagine we want to add a property address to model Sample\House and this property would have type Sample\Place (same type as property birthPlace in model Sample\Person). Now we want a person born in certain place or a person that have a house in certain place. But this request case is impossible to resolve in intermediate request because we are not able to determine on which property apply the literal (literal only describe model). Fortunately we can manage this problem with advanced request.
  • sql request building via Intermadiate request can take more time than via advanced request. However that can be negligible compared sql query execution time. It depend on your database size and complexity.

Advanced request format

The advanced request format correspond to model Comhon\Request\Complex.
You can see associated manifest here.

In advanced request format you must define relations between properties linked to a literal. These relations are display in a graph (actually in a tree) which each node is a property except root node that is your requested model object. And each literal refer to a node of this graph.

Use case 1

States

I want persons
-that have a grandson named walter
-and that have a house without garden

Request

{
    "simple_collection": [
        {
            "id": 0,
            "elements": [
                1,
                2
            ],
            "type": "conjunction",
            "inheritance-": "Comhon\\Logic\\Simple\\Clause"
        },
        {
            "id": 1,
            "node": 3,
            "property": "firstName",
            "operator": "=",
            "value": "walter",
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\String"
        },
        {
            "id": 2,
            "node": 1,
            "property": "garden",
            "operator": "=",
            "value": false,
            "inheritance-": "Comhon\\Logic\\Simple\\Literal\\Boolean"
        }
    ],
    "filter": 0,
    "tree": {
        "id": 0,
        "model": "Sample\\Person",
        "nodes": [
            {
                "id": 1,
                "property": "houses"
            },
            {
                "id": 2,
                "property": "children",
                "nodes": [
                    {
                        "id": 3,
                        "property": "children"
                    }
                ]
            }
        ]
    },
    "inheritance-": "Comhon\\Request\\Complex"
}

Result

Stringified ComhonArray :

[
    {
        "id": 1,
        "firstName": "john",
        "lastName": "doe",
        "birthPlace": 1,
        "father": null,
        "mother": null,
        "inheritance-": "Sample\\Person\\Man"
    }
]

Explanations

The tree
visualization

To have a better comprehension here is the tree in more visual way :

                  person (0)
           ___________|__________
          |                      |
    children (2)          houses (1)
          |
    children (3)
node

Each node tree has :

  • property or model
    • root node contain model that is the model name of requested objects.
    • other nodes contain property that is a property name of the model of the parent node.
  • id identifier of current node.
  • nodes that contain children properties of current model node (optional)
Literal

In advanced request, literals node value refer to tree node instead of models node in intermediate request.

Order, offset and limit

  • We can order returned objects. Order can be applied on one or several properties of requested model. We can order in ascendant or descendant way (ASC or DESC).
  • We can apply a limit of returned objects
  • We can apply an offset to return objects from a certain range

To apply limit or offset we must specify order too. Actually if order is not specified, two same objects requests can return objects in different order, so returned objects may not be the same with a limit.

Example : I want five persons maximum, from third person, order by their firstname

{
    "root": 0,
    "models": [
        {
            "id": 0,
            "model": "Sample\\Person"
        }
    ],
    "limit" : 5,
    "offset" : 3,
    "order" : [{"property":"firstName", "type":"ASC"}],
    "inheritance-": "Comhon\\Request\\Intermediate"
}

Returned properties

Returned properties may be filtered.

{
    "tree": {
        "id": 0,
        "model": "Sample\\Person"
    },
    "properties" : ["firstName", "birthPlace"],
    "inheritance-": "Comhon\\Request\\Complex"
}

Returned objects will only contain firstName, birthPlace and id (identifiers are automatically added even if they don't are in list).

Count

Instead of retrieve objects, it is possible to count objects that match built request. count function return the global count of object and ignore limit and offset even if they are set on built request. This function is usefull for pagination.

$requester = ComplexRequester::build($request);
$result = $requester->count(); // return integer

It is possible to call count and execute on same built request.

$requester = ComplexRequester::build($request);
$collection = $requester->execute(); // return ComhonArray
$count = $requester->count(); // return integer

Clone this wiki locally