Define relationships in Emergence Active Records


#1

You can define relationships in your Active Record classes and use Emergence’s RecordsRequestHandler to automatically retrieve related data.

One to Many relationships

In the following DB structure, Movies and Directors have a one to many relationship. A Movie can have one Director, specified by the DirectorID field, and individual Directors can be associated with multiple Movies.

Relationship Diagram

We can create a class extending the Emergence ActiveRecord class to represent the Movie table like this:

class Movie extends \ActiveRecord
{
    // ActiveRecord configuration
    public static $tableName = 'movies';
    public static $singularNoun = 'movie';
    public static $pluralNoun = 'movies';
    public static $collectionRoute = '/movies';

    public static $fields = [
        'Title' => [
            'default' => null
        ],
        'DirectorID' => [
            'type' => 'uint',
            'default' => null
        ]
    ];
}

Note: We do not specify the default Emergence fields (ID,Class,Created,CreatorID) as they are defined in the ActiveRecord class we are extending.

We create a similar class to represent the Director Table:

class Director extends \ActiveRecord
{
    // ActiveRecord configuration
    public static $tableName = 'directors';
    public static $singularNoun = 'director';
    public static $pluralNoun = 'directors';
    public static $collectionRoute = '/directors';

    public static $fields = [
        'DirectorName' => [
            'default' => null
        ]
    ];
}

Now we can specify a Movie’s relationship to a director by defining the static $relationships array, and expose the related data defining the static $dynamicFields array. Since one Movie can have only one Director, we will define the relationship type as “one-one”. Our new class would look like this:

class Movie extends \ActiveRecord
{
    // ActiveRecord configuration
    public static $tableName = 'movies';
    public static $singularNoun = 'movie';
    public static $pluralNoun = 'movies';
    public static $collectionRoute = '/movies';

    public static $fields = [
        'Title' => [
            'default' => null
        ],
        'DirectorID' => [
            'type' => 'uint',
            'default' => null
        ]
    ];

    public static $relationships = [
        'Director' => [
            'type' => 'one-one', // One movie record relates to one director
            'local' => 'DirectorID', // If not specified, ActiveRecord will assume the local key is "DirectorID"
            'foreign' => 'ID',  // If not specified, ActiveRecord will assume the foreign key is "ID"
            'class' => Director::class
        ]
    ];

    public static $dynamicFields = [
        'Director'
    ];
}

Let’s enter a few rows in the DB, hook up an Emergence RecordsRequestHandler, and see our result at http://example.com/movies/json:

{
    "success": true,
    "data": [
        {
            "ID": 1,
            "Class": "Movie",
            "Created": 1445928421,
            "CreatorID": 1,
            "Title": "Pulp Fiction",
            "DirectorID": 1
        },
        {
            "ID": 2,
            "Class": "Movie",
            "Created": 1446178463,
            "CreatorID": 1,
            "Title": "Reservoir Dogs",
            "DirectorID": 1
        },
        {
            "ID": 3,
            "Class": "Movie",
            "Created": 1446245834,
            "CreatorID": null,
            "Title": "Stranger Than Paradise",
            "DirectorID": 2
        }
    ],
    "conditions": [],
    "total": 3,
    "limit": false,
    "offset": false
}

We are getting the DirectorID field, but we’d also like the complete Director record so let’s include it in the URL:

http://example.com/movies/json?include=Directors . Note that the name of the include parameter corresponds to both the name of the relation in the $relationships array and the name of the field defined in the $dynamicFields array.

{
    "success": true,
    "data": [
        {
            "ID": 1,
            "Class": "Movie",
            "Created": 1445928421,
            "CreatorID": 1,
            "Title": "Pulp Fiction",
            "DirectorID": 1,
            "Directors": {
                "ID": 1,
                "Class": "Director",
                "Created": 1445367354,
                "CreatorID": 1,
                "DirectorName": "Quentin Tarantino"
            }
        },
        {
            "ID": 2,
            "Class": "Movie",
            "Created": 1446178463,
            "CreatorID": 1,
            "Title": "Reservoir Dogs",
            "DirectorID": 1,
            "Directors": {
                "ID": 1,
                "Class": "Director",
                "Created": 1445367354,
                "CreatorID": 1,
                "DirectorName": "Quentin Tarantino"
            }
        },
        {
            "ID": 3,
            "Class": "Movie",
            "Created": 1446245834,
            "CreatorID": 1,
            "Title": "Stranger Than Paradise",
            "DirectorID": 2,
            "Directors": {
                "ID": 2,
                "Class": "Director",
                "Created": 1445533478,
                "CreatorID": 1,
                "DirectorName": "Jim Jarmusch"
            }
        }
    ],
    "conditions": [],
    "total": 3,
    "limit": false,
    "offset": false
}

As the above result shows, we are now able to retrieve Movie records with their associated Director Record.

Many to One relationships

We can also retrieve this relational data from the other direction, specifically we can retrieve Directors with their associated Movie records. To do this we will define a Director’s relationship to a Movie. Since a Director can have multiple Movies, we will define the relationship type as “one-many”. Our new Director class would look like this:

class Director extends \ActiveRecord
{
    // ActiveRecord configuration
    public static $tableName = 'directors';
    public static $singularNoun = 'director';
    public static $pluralNoun = 'directors';
    public static $collectionRoute = '/directors';

    public static $fields = [
        'DirectorName' => [
            'default' => null
        ]
    ];

    public static $relationships = [
        'Movies' => [
            'type' => 'one-many', // One director can relate to many movies
            'local' => 'ID', // If not specified, ActiveRecord will assume the local key is "ID"
            'foreign' => 'DirectorID',
            'class' => Movie::class
        ]
    ];

    public static $dynamicFields = [
        'Movies'
    ];
}

If we include Movies in our Directors request, eg http://example.com/directors/json?include=Movies , we will see our Director records are retrieved with their associated Movie Records.

{
    "success": true,
    "data": [
        {
            "ID": 1,
            "Class": "Director",
            "Created": 1445367354,
            "CreatorID": 1,
            "DirectorName": "Quentin Tarantino",
            "Movies": [
                {
                    "ID": 1,
                    "Class": "Movie",
                    "Created": 1445928421,
                    "CreatorID": 1,
                    "Title": "Pulp Fiction",
                    "DirectorID": 1
                },
                {
                    "ID": 2,
                    "Class": "Movie",
                    "Created": 1446178463,
                    "CreatorID": 1,
                    "Title": "Reservoir Dogs",
                    "DirectorID": 1
                }
            ]
        },
        {
            "ID": 2,
            "Class": "Director",
            "Created": 1445533478,
            "CreatorID": 1,
            "DirectorName": "Jim Jarmusch",
            "Movies": [
                {
                    "ID": 3,
                    "Class": "Movie",
                    "Created": 1446245834,
                    "CreatorID": 1,
                    "Title": "Stranger Than Paradise",
                    "DirectorID": 2
                }
            ]
        }
    ],
    "conditions": [],
    "total": 2,
    "limit": false,
    "offset": false
}

Many to Many relationships

coming soon