Skip to content

Instantly share code, notes, and snippets.

@mykeels
Created August 5, 2018 11:25
Show Gist options
  • Save mykeels/34a731e36cd131a55c4172249ec1ba46 to your computer and use it in GitHub Desktop.
Save mykeels/34a731e36cd131a55c4172249ec1ba46 to your computer and use it in GitHub Desktop.
Extending Models with Content and Content-Type

Extending Models with Content and Content-Type

Traditional relational databases have structure, so we use migrations to manage that structure in Laravel.

This is cool, until you find yourself creating tables for things that you don't need tables for, because none of the tables' columns act as foreign keys to keys on other tables.

E.g. a user_settings table would have a structure like

id user_id key value
1 2 bg_color red
2 3 bg_color blue

Now, if you wanted to store more complicated information like what ring-tone to play when a particular user calls, you'd have to either extend the user_settings with a migration to have a column like target_user_id, or have a nested key like <target-user-id>/ringtone.

Either choice would present some challenge, grouping settings to resolve during presentation.

Presenting Content and Content-Type

These represent two Eloquent models that map to tables with schema:

ContentType

name type description
id int Incremental ID
model varchar A reference to class name of the Eloquent Model that owns this
name varchar A lower-case name of the content-type e.g. bg_color
display_name varchar A more user-friendly name, in case you need to display
format varchar One of string, number, boolean, datetime, object or array
related_to int A reference to another ContentType id that this is a child of
created_at timestamp When this was created
updated_at timestamp When last this was updated

Content

name type description
id int Incremental ID
model_id int A reference to the id of the model instance that owns this content
content_type_id int A reference to the content-type that this content belongs to
value varchar The actual value of this content
created_at timestamp When this was created
updated_at timestamp When last this was updated

Rules

  • Only a content-type with an array format is allowed to have multiple contents.
  • Only a content-type with an object format is allowed to have child content-type(s).
  • A child content-type is one with its related_to value set to the id of another content-type.
  • For content-type(s) with primitive format values, the values of their content must match with their formats. E.g. a content-type with number format, can only have a content with a number value such as 100 or 0.2345.

The Advantage(s)

  • When retrieving contents, the response can extend an existing model with $builder->with('contents.type'). Here's an example of content for a department model:
{
    "id": 1,
    "name": "Physics",
    "hod_id": 1,
    "faculty_id": 1,
    "created_at": "2018-08-01 08:23:36",
    "updated_at": "2018-08-01 08:23:36",
    "contents": [
        {
            "id": 1,
            "owner_id": 1,
            "content_type_id": 1,
            "value": "array-value-1",
            "created_at": "2018-08-01 08:23:36",
            "updated_at": "2018-08-01 08:23:36",
            "type": {
                "id": 1,
                "school_id": 1,
                "type": "App\\Models\\Department",
                "name": "type-1",
                "display_name": "Type 1",
                "format": "array",
                "related_to": null,
                "created_at": "2018-08-01 08:23:36",
                "updated_at": "2018-08-01 08:23:36"
            }
        }
    ]
}
  • The response can be transformed to become nested, and include only important details.
{
    "id": 1,
    "name": "Physics",
    "hod_id": 1,
    "faculty_id": 1,
    "created_at": "2018-08-01 08:23:36",
    "updated_at": "2018-08-01 08:23:36",
    "content": {
        "type-1": [
            "array-value-1",
            "array-value-2",
            "array-value-3"
        ],
        "type-9": "Value 1",
        "type-6": {
            "type-4": "object-value-1",
            "type-8": 123
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment