Quickstart
Introduction
To record an activity, prepare the models, define a headline, and publish the activity from your application. This example records a customer placing an order with a shop.
Preparing the Models
Install Storyfeed before defining your models and headline.
To include the Order model in an activity, implement the Feedable interface and use the InteractsWithFeed trait. Define its label in the toFeed method:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Storyfeed\Concerns\InteractsWithFeed;
use Storyfeed\Contracts\Feedable;
use Storyfeed\FeedEntity;
class Order extends Model implements Feedable
{
use InteractsWithFeed;
public function toFeed(): FeedEntity
{
return FeedEntity::make()->label("Order #{$this->reference}");
}
}<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Storyfeed\Concerns\InteractsWithFeed;
use Storyfeed\Contracts\Feedable;
use Storyfeed\FeedEntity;
class Order extends Model implements Feedable
{
use InteractsWithFeed;
public function toFeed(): FeedEntity
{
return FeedEntity::make(
label: "Order #{$this->reference}",
);
}
}For the Shop and User models, implement Feedable and use InteractsWithFeed as well. If you omit the toFeed method, Storyfeed generates a default label from the model's attributes, such as name.
Defining a Headline
Define a headline for the place verb in routes/feed.php:
use App\Models\Order;
use Storyfeed\Facades\Story;
Story::for(Order::class)->verb('place')
->headline(':actor placed :object with :target');Publishing an Activity
Publish the activity where your application places the order:
use Storyfeed\Facades\Storyfeed;
Storyfeed::activity()
->by($customer)
->action('place', $order)
->to($shop)
->publish();use Storyfeed\Facades\Storyfeed;
Storyfeed::record(
verb: 'place',
object: $order,
actor: $customer,
target: $shop,
);Retrieving the Feed
To retrieve a page of activities, call the feed method on the Storyfeed facade, followed by the get method. You may return the result from a route:
use Illuminate\Support\Facades\Route;
use Storyfeed\Facades\Storyfeed;
Route::get('/', function () {
return Storyfeed::feed()->get();
});The route returns a JSON payload:
{
"payload_version": 1,
"items": [
{
"kind": "activity",
"id": "j84",
"verb": "place",
"published_at": "1985-07-02T12:00:00.000000Z",
"headline_template": ":actor placed :object with :target",
"headline": null,
"glyph": null,
"glyph_intent": null,
"actor": {
"type": "user",
"id": "113",
"label": "Erica Sinclair",
"url": null,
"attributes": {},
"modal": false,
"data": {},
"media": null,
"body": null,
"tombstone": null
},
"object": {
"type": "order",
"id": "1035",
"label": "Order #1035",
"url": null,
"attributes": {},
"modal": false,
"data": {},
"media": null,
"body": null,
"tombstone": null
},
"target": {
"type": "venue",
"id": "101",
"label": "Scoops Ahoy",
"url": null,
"attributes": {},
"modal": false,
"data": {},
"media": null,
"body": [
{
"$body": "Storyfeed/Body/Image",
"$v": 1,
"caption": "Scoops Ahoy",
"alt": "Scoops Ahoy",
"width": null,
"height": null,
"image": "preview"
}
],
"tombstone": null
},
"context": null,
"origin": null,
"result": null,
"instrument": null,
"data": {},
"tombstoned": [],
"redundant": false,
"missing_headline_template": null,
"missing_headline": null
}
],
"next_cursor": "eyJwIjoiMjAyNi0wOC0xNFQxNDowNTowMFoifQ",
"sync_token": "01J8Z3K4Q2V9WMX7R5T0B6N1CD"
}Storyfeed is headless: it has no views
Storyfeed serializes the feed as a structured payload, and your frontend chooses how to render it. For Blade, Storyfeed UI renders it with one component.
See Rendering to display the feed with Blade or Vue.