Database
Confetti CMS features a built-in Object-Relational Mapping (ORM) system that simplifies database interactions.
Since Confetti knows which fields are needed, it fetches all the data in a single query. This eliminates the common n+1 query problem, ensuring fast performance without extra effort, so you can focus on building your website while the ORM handles efficient data management in the background.
For example, consider a list with titles created as follows:
@php($page = newRoot(new \model\page))
@foreach ($page->list('block')->get() as $block)
{{ $block->text('title') }}
@endforeach
With automatically generated models and query classes, you can retrieve data such as the title of the first block using:
{{ \model\page\block_list::query()->first()->title }}
You can even add new fields:
@php($block = \model\page\block_list::query()->first())
{{ $block->text('description') }}
Note: In PhpStorm, the generated code only becomes visible after it has been indexed. This happens when you switch windows.
The ORM provides several methods to filter and manipulate queries:
first()
Retrieve the first item in the list.
$block = \model\page\block_list::query()->first();
where(string|ComponentStandard $key, string $operator, mixed $value)
Filter the list based on a specified condition.
$blocks = \model\page\block_list::query()->where('is_active', '=', true)->get();
Alternatively, use the automatically generated banner is_active class:
use \model\homepage\banner_list\is_active;
$blocks = \model\page\block_list::query()->where(new is_active, '=', true)->get();
orderAscBy(string|ComponentStandard $key)
Sort the list in ascending or descending order. Ascending is the default.
$blocks = \model\page\block_list::query()->orderAscBy('title')->get();
$blocks = \model\page\block_list::query()->orderDescBy('title')->get();
Use ->sortable()
to enable user-driven sorting in the admin panel. Default order is descending.
limit(int $limit)
Restrict the number of items returned.
$blocks = \model\page\block_list::query()->limit(5)->get();
offset(int $offset)
Skip a specified number of items before returning results.
$blocks = \model\page\block_list::query()->offset(5)->get();
$banner = $homepage->list('banner')->first();
{{ $banner->text('title') }}
{{ $banner->title }}
@foreach($homepage->list('block')->get() as $banner)
{{ $banner->text('title') }}
@foreach($banner->list('carousel')->sortable()->get() as $carousel)
{!! $carousel->image('image')->getPicture() !!}
@endforeach
@endforeach
Paginated Blog Posts List
File: view/blog_overview.blade.php
@php
$perPage = 10;
$page = request()->parameter('page') ?: 1;
$offset = ($page - 1) * $perPage;
$blogPage = newRoot(new \model\blog_overview);
$blogs = $blogPage->list('blog')->columns(['title'])->limit($perPage)->offset($offset)->get();
@endphp
<div class="bg-gray-50 py-8">
<ul class="space-y-8 max-w-4xl mx-auto">
@foreach($blogs as $blog)
<li class="bg-white rounded-lg shadow p-6">
<div class="flex justify-between items-start">
<h3 class="text-2xl font-semibold text-blue-500">{{ $blog->text('title')->min(1)->max(50)->bar(['b', 'i', 'u']) }}</h3>
</div>
<div class="mt-4">
<a href="/blogs/{{ $blog->text('slug')->min(1)->max(50) }}" class="text-blue-500">Read more</a>
</div>
</li>
@endforeach
</ul>
<div class="mt-8 flex justify-center">
@if($page > 1)
<a href="{{ request()->uri() }}?page={{ $page-1 }}" class="bg-blue-500 text-white px-4 py-2 rounded-lg mr-2">Previous</a>
@endif
@if(count($blogs) === $perPage && $blogPage->blogs()->offset($offset + 1)->first() !== null)
<a href="{{ request()->uri() }}?page={{ $page+1 }}" class="bg-blue-500 text-white px-4 py-2 rounded-lg">Next</a>
@endif
</div>
</div>
Blog Post Detail Page
File: view/blog_detail.blade.php
@php
$alias = str_replace('/blogs/', '', request()->uri());
$blog = \model\blog_overview\blog_list::query()->whereSlugIs($alias)->first();
@endphp
<main class="max-w-3xl mx-auto">
<article class="relative pt-12">
<a href="/blogs" class="bg-blue-500 text-white px-4 py-2 rounded-lg mr-2">Back to overview</a>
<div class="rounded-lg p-4 text-xl flex justify-center m-8">
<h1>{{ $blog->title }}</h1>
</div>
<div class="font-body">
<div class="mx-4 w-full">
{!! $blog->image('image')->widthPx(800)->getPicture(class: 'relative w-full sm:w-220 p-3 rounded-lg') !!}
@include('website.includes.blocks.index', ['model' => $blog->content('content')])
</div>
</div>
</article>
</main>
Note how the blog is queried using the ->query()
method on the \model\blog_overview\blog_list
class. You can reuse fields like ->title
or access new components such as $blog->image('image')
.
Registering Blog Post URLs
In the view/index.blade.php
file, you can register blog post URLs using a basic routing system:
@switch(true)
@case(request()->uri() === '/blogs')
@include('view.blog_overview')
@break
@case(str_starts_with(request()->uri(), '/blogs/'))
@include('view.blog_detail')
@break
// ...
@endswitch