PageService
High-level API for loading, listing, and managing pages with caching and events.
Namespace: VelvetCMS\Services\PageService
Definition #
class PageService
{
public function __construct(
ContentDriver $driver,
EventDispatcher $events,
CacheDriver $cache,
CacheTagManager $cacheTags
);
public function load(string $slug): Page;
public function save(Page $page): bool;
public function list(array $filters = []): Collection;
public function delete(string $slug): bool;
public function exists(string $slug): bool;
public function published(): Collection;
public function drafts(): Collection;
public function recent(int $limit = 5): Collection;
public function count(): int;
}
Accessing PageService #
// Via container
$pages = app('pages');
// Via helper
$pages = pages();
Methods #
load() #
Load a page by slug. Results are cached for 300 seconds.
public function load(string $slug): Page
| Parameter | Type | Description |
|---|---|---|
$slug |
string |
The page slug |
Returns: Page instance
Throws: NotFoundException if page doesn't exist
Events: page.loading, page.loaded
Example:
$pages = app('pages');
try {
$page = $pages->load('welcome');
echo $page->title;
echo $page->content;
} catch (NotFoundException $e) {
// Handle 404
}
save() #
Save a page (create or update). Automatically sets createdAt and updatedAt timestamps.
public function save(Page $page): bool
| Parameter | Type | Description |
|---|---|---|
$page |
Page |
The page to save |
Returns: true on success
Events: page.saving, page.saved
Cache: Clears individual page cache and flushes list cache tag
Example:
$page = new Page();
$page->slug = 'about';
$page->title = 'About Us';
$page->content = '# About\n\nWelcome to our site.';
$page->status = 'published';
$pages->save($page);
Updating an existing page:
$page = $pages->load('about');
$page->title = 'About Our Company';
$page->content .= '\n\nUpdated content.';
$pages->save($page);
list() #
Get all pages matching filters. Results are cached using tags for 300 seconds.
public function list(array $filters = []): Collection
| Parameter | Type | Description |
|---|---|---|
$filters |
array |
Optional filter criteria |
Returns: Collection of Page objects
Example:
// All pages
$all = $pages->list();
// With filters
$recent = $pages->list([
'status' => 'published',
'order_by' => 'updated_at',
'order' => 'desc',
'limit' => 10,
]);
delete() #
Delete a page by slug.
public function delete(string $slug): bool
| Parameter | Type | Description |
|---|---|---|
$slug |
string |
The page slug |
Returns: true on success
Throws: NotFoundException if page doesn't exist
Events: page.deleting, page.deleted
Cache: Clears individual page cache and flushes list cache tag
Example:
try {
$pages->delete('old-page');
} catch (NotFoundException $e) {
// Page didn't exist
}
exists() #
Check if a page exists (not cached).
public function exists(string $slug): bool
Example:
if (!$pages->exists('welcome')) {
$this->createDefaultPage();
}
published() #
Get all published pages.
public function published(): Collection
Example:
$publishedPages = $pages->published();
foreach ($publishedPages as $page) {
echo $page->title . "\n";
}
drafts() #
Get all draft pages.
public function drafts(): Collection
Example:
$draftPages = $pages->drafts();
$this->info("You have {$draftPages->count()} drafts.");
recent() #
Get recently updated pages.
public function recent(int $limit = 5): Collection
| Parameter | Type | Default | Description |
|---|---|---|---|
$limit |
int |
5 |
Number of pages to return |
Example:
$recentPages = $pages->recent(10);
count() #
Get total page count.
public function count(): int
Example:
$total = $pages->count();
echo "Total pages: {$total}";
Caching Behavior #
PageService implements intelligent caching:
| Operation | Cache Key | TTL | Behavior |
|---|---|---|---|
load() |
page:{slug} |
300s | Individual page cached |
list() |
pages:list:{hash} |
300s | Tagged with pages:list |
save() |
- | - | Clears page:{slug}, flushes pages:list tag |
delete() |
- | - | Clears page:{slug}, flushes pages:list tag |
Example of cache invalidation:
// This is cached
$page = $pages->load('about'); // Cache HIT after first call
// Saving invalidates the cache
$page->title = 'New Title';
$pages->save($page);
// Next load fetches fresh data
$page = $pages->load('about'); // Cache MISS, fresh data
Events #
PageService dispatches these events:
| Event | Payload | Description |
|---|---|---|
page.loading |
string $slug |
Before loading a page |
page.loaded |
Page $page |
After page is loaded |
page.saving |
Page $page |
Before saving a page |
page.saved |
Page $page |
After page is saved |
page.deleting |
string $slug |
Before deleting a page |
page.deleted |
string $slug |
After page is deleted |
Example listeners:
$events = app('events');
// Log page views
$events->listen('page.loaded', function(Page $page) {
app('analytics')->trackPageView($page->slug);
});
// Notify on publish
$events->listen('page.saved', function(Page $page) {
if ($page->status === 'published') {
app('notifications')->notifySubscribers($page);
}
});
// Clear CDN on delete
$events->listen('page.deleted', function(string $slug) {
app('cdn')->purge("/pages/{$slug}");
});
Usage Examples #
Controller Example #
class PageController
{
public function __construct(
private readonly PageService $pages
) {}
public function show(Request $request, string $slug): Response
{
try {
$page = $this->pages->load($slug);
if ($page->status !== 'published') {
throw new NotFoundException();
}
return Response::html(view('pages.show', [
'page' => $page,
]));
} catch (NotFoundException $e) {
throw new NotFoundException("Page not found: {$slug}");
}
}
public function index(): Response
{
$pages = $this->pages->published();
return Response::html(view('pages.index', [
'pages' => $pages,
]));
}
}
Admin CRUD Example #
class AdminPageController
{
public function __construct(
private readonly PageService $pages
) {}
public function store(Request $request): Response
{
$data = $request->validate([
'slug' => 'required|string',
'title' => 'required|string',
'content' => 'required|string',
'status' => 'in:draft,published',
]);
if ($this->pages->exists($data['slug'])) {
return Response::json([
'error' => 'Page already exists',
], 409);
}
$page = new Page();
$page->slug = $data['slug'];
$page->title = $data['title'];
$page->content = $data['content'];
$page->status = $data['status'] ?? 'draft';
$this->pages->save($page);
return Response::json(['data' => $page], 201);
}
public function update(Request $request, string $slug): Response
{
$page = $this->pages->load($slug);
$data = $request->validate([
'title' => 'string',
'content' => 'string',
'status' => 'in:draft,published',
]);
if (isset($data['title'])) {
$page->title = $data['title'];
}
if (isset($data['content'])) {
$page->content = $data['content'];
}
if (isset($data['status'])) {
$page->status = $data['status'];
}
$this->pages->save($page);
return Response::json(['data' => $page]);
}
public function destroy(string $slug): Response
{
$this->pages->delete($slug);
return Response::json(['message' => 'Deleted']);
}
}
CLI Command Example #
class ListPagesCommand extends Command
{
public function __construct(
private readonly PageService $pages
) {}
public function signature(): string
{
return 'pages:list';
}
public function description(): string
{
return 'List all pages';
}
public function handle(): int
{
$status = $this->option('status');
$pages = $status
? $this->pages->list(['status' => $status])
: $this->pages->list();
$this->table(
['Slug', 'Title', 'Status', 'Updated'],
$pages->map(fn($p) => [
$p->slug,
$p->title,
$p->status,
$p->updatedAt?->format('Y-m-d H:i'),
])->toArray()
);
return 0;
}
}