Resolving Bodies When Retrieved
Resolve a body when its values must reflect the current model rather than the stored snapshot. Use FeedMedia::body() in the model's feedMedia() method; use Activity Content for bodies stored by toFeed(). Feed Media covers links, files, picture slots, and avatars.
Using Current Values
Return a body from feedMedia() to use the model's current values:
use Storyfeed\Body\KeyValue;
use Storyfeed\FeedContext;
use Storyfeed\FeedMedia;
public static function feedMedia(FeedContext $context): ?FeedMedia
{
return FeedMedia::make()
->body(
KeyValue::make()
->items('Portions left', $context->model()?->portions_left),
);
}use Storyfeed\Body\KeyValue;
use Storyfeed\FeedContext;
use Storyfeed\FeedMedia;
public static function feedMedia(FeedContext $context): ?FeedMedia
{
return FeedMedia::make(
body: KeyValue::make(
items: ['Portions left' => $context->model()?->portions_left],
),
);
}Stored and resolved bodies share the same payload shape. When toFeed() and feedMedia() both return bodies, the item includes both, with stored bodies first. Your renderer controls the layout.
Choosing Stored or Current Values
Choose when a value is decided:
| Method | When It Runs | Value |
|---|---|---|
->data(…) on the activity | when the activity is published | frozen at publication |
->body(…) on FeedEntity in toFeed() | whenever the model is saved | stored and updated with the model |
->body(…) on FeedMedia in feedMedia() | whenever the feed is retrieved | built from current values and never stored |
See Computed Values in the Feed for publication-time facts and counts computed on retrieval.
Deferring Body Construction
The resolver runs whenever the feed is retrieved. Pass a closure to defer building the body until the payload needs it:
use Storyfeed\Body\KeyValue;
use Storyfeed\FeedContext;
use Storyfeed\FeedMedia;
public static function feedMedia(FeedContext $context): ?FeedMedia
{
return FeedMedia::make()->body(
fn (): KeyValue => KeyValue::make()
->items('Portions left', $context->model()?->portions_left),
);
}use Storyfeed\Body\KeyValue;
use Storyfeed\FeedContext;
use Storyfeed\FeedMedia;
public static function feedMedia(FeedContext $context): ?FeedMedia
{
return FeedMedia::make(
body: fn (): KeyValue => KeyValue::make(
items: ['Portions left' => $context->model()?->portions_left],
),
);
}Loading models takes one query per model class on the page. If the resolver throws, Storyfeed reports the error once per class and omits that body. The activity keeps its label, link, and other bodies. Use a closure when the body needs current model data; bodies built from the snapshot can be passed directly.
Accessing Resolver Data
The resolver runs for every entity on the page. Use $context->data() for the snapshot or $context->model() for the current model. The latter loads all models of that class on the page together. Pass relations to $context->model(with: […]) to load them together too. A query such as $model->orders()->count() runs once per entity, so use a counter column on the model to avoid repeated queries.