Streams

Code-configured domain information.

Introduction

The Streams platform leans heavily on domain-driven design (DDD). We call these domain abstractions streams, hence our namesake.

An example could be configuring a domain model (a stream) for a website's pages, users of an application, or feedback submissions from a form.

Defining Streams

Using JSON files, you can define stream configurations in the streams/ directory. The filenames serve as the stream's id.

It is highly encouraged to use the plural form of a noun when naming Streams—for example, contacts and people. Also, naming conventions like business_contacts or neat-people work well.

The Basics

To get started, you need only specify the id, which is the filename itself, and some fields to describe the domain object's structure.

Let's create a little stream to hold information for a simple CRM.

// streams/contacts.json
{
    "name": "Contacts",
    "config": {
        "source": {
            "type": "filebase",
            "filename": "streams/data/contacts",
            "format": "json"
        },
        "abstract": "Streams\\Core\\Entry\\Entry",
        "criteria": "Streams\\Core\\Criteria\\Criteria",
        "repository": "Streams\\Core\\Repository\\Repository",
        "collection": "Illuminate\\Support\\Collection",
    },
    "fields": {
        "name": "string",
        "email": "email",
        "company": {
            "type": "relationship",
            "config": {
                "related": "companies"
            }
        }
    }
}

Fields

Fields are an essential descriptor of the domain object. They describe what properties the domain object will have and how they work. Field types control things like accessors, data mutation, and casting.

The field configuration keys serve as a handle, which you can use to reference the field later. So, for example, you may access the above contact fields like this:

$entry->email;
$entry->company->email;

Stream Routes

Streams can simplify routing by defining associated routes in their definition.

// streams/contacts.json
{
    "routes": {
        "index": "contacts",
        "view": "contacts/{id}"
    }
}

You can also use an array to include other route options.

// streams/contacts.json
{
    "routes": {
        "contact": {
            "csrf": false,
            "uri": "form/{entry.email}"
        }
    }
}

Stream Validation

Streams simplifies validation by defining validation in their definition.

// streams/contacts.json
{
    "rules": {
        "name": [
            "required",
            "max:100"
        ],
        "email": [
            "required",
            "email:rfc,dns"
        ],
        "company": "required|unique"
    }
}

Security

Specify the Laravel policy to use for security.

// streams/contacts.json
{
    "policy": "App\\Contacts\\ContactPolicy"
}

Caching

Streams provides a touch-free caching system you can define in the configuration.

// streams/contacts.json
{
    "cache": false,
    "ttl": 1800 // 30 minutes
}

Sources

Sources define the source information for entry data which you can define in the configuration.

// streams/contacts.json
{
    "source": {
        "type": "filebase",
        "format": "md"
    }
}

Stream Entries

Domain entities are called entries within the Streams platform. A stream defines entry attributes, or fields, that dictate the entry's properties, data-casting, and more.

Abstracts

The abstract parameter defines the class to use when constructing entry instances.

// streams/contacts.json
{
    "abstract": "App\\Contacts\\Contact"
}

When defining Elqouent stream sources, the sources model will be used as the abstract.

Criteria

The criteria parameter defines the class to use when building entry queries.

// streams/contacts.json
{
    "criteria": "App\\Contacts\\ContactCriteria"
}

Repositories

The repository parameter defines the repository class to use for the stream entries.

// streams/contacts.json
{
    "repository": "App\\Contacts\\ContactRepository"
}

Advanced Streams

JSON References

You can use JSON file references within stream configurations to point to other JSON files using the @ symbol followed by a relative path to the file. In this way, you can reuse various configuration information or tidy up larger files. The referenced file's JSON data directly replaces the reference.

// streams/contacts.json
{
    "name": "Contacts",
    "fields": "@streams/fields/contacts.json"
}
// streams/fields/contacts.json
{
    "name": "string",
    "email": "email",
    "company": {
        "type": "relationship",
        "stream": "company"
    }
}

Extend a Stream

A stream can extend another stream, which works like a recursive merge.

// streams/family.json
{
    "name": "Family Members",
    "extend": "contacts",
    "fields": {
        "relation": {
            "type": "select",
            "config": {
                "options": {
                    "mother": "Mother",
                    "father": "Father",
                    "brother": "Brother",
                    "sister": "Sister"
                }
            }
        }
    }
}

In the above example, all contacts fields are available to you, as well as the new relation field.

$entry->email;      // The email value.
$entry->relation;   // The relation value.

Stream Sources

You can configure the flat-file database as well as other sources for storing data including any Laravel database. No code changes required.