Gerçek bir uygulama için sorun, Live Components’ın çıkışıyla acil hale geldi ve sunucu tarafı rendering, etkileşimli UI’lar için gerçekten rekabetçi hale geldi.
<hr/>
<h2>
<a name="the-case-for-going-fully-serverside" href="#the-case-for-going-fully-serverside"></a>
Tamamen Sunucu Tarafına Geçişin Gerekliliği
</h2>
<p>Belirgin bir itiraz, gecikmedir. Her kullanıcı etkileşiminin bir sunucu turu gerektirmesi, kullanıcıların bunu fark etmesine neden olmaz mı?</p>
<p>Pratikte hayır — uygulama yeterince optimize edilirse. Modern altyapılar, önbellekli veya basit sorgular için yanıtları 20-80ms içinde sunar. Livewire veya UX Live'daki algılanan etkileşim hızı, çoğu etkileşim için iyi yazılmış bir Vue bileşeni ile karşılaştırılabilir. Livewire ekibi benchmark'lar yayınladı; UX Live belgeleri de aynı şeyi gösteriyor. Bu artık teorik bir argüman değil — üretim uygulamaları bunu kanıtlıyor.</p>
<p>Daha önemlisi: sunucunuz yavaşsa, bu, sunucu tarafı bileşenleri kullanıp kullanmadığınıza bakılmaksızın çözmeniz gereken bir sorundur. Önbellekleme, sorgu optimizasyonu ve doğru altyapı, bir üretim uygulamasında isteğe bağlı değildir. Sunucu tarafı bileşenleri, performans özelliklerini açık ve ölçülebilir hale getirir, bu da onları bir siyah kutu JS paketine gizlenmiş olmaktan çıkarır.</p>
<p>Tamamen sunucu tarafına geçişin takvimler için gerçek faydaları oldukça önemlidir:</p>
<ul>
<li><strong>Hiçbir hidratasyon yok.</strong> Sunucu, takvimi her istekte render eder. Sunucu ve istemci arasında senkronize edilecek bir durum yoktur çünkü sadece bir doğruluk kaynağı vardır.</li>
<li><strong>Navigasyon için hiç JS yok.</strong> “Sonraki ay”a tıkladığınızda bir sunucu eylemi çağrılır. Bileşen yeni ay ile tekrar render edilir. Tamam.</li>
<li><strong>Veri yükleme basittir.</strong> Veritabanınıza PHP ile sorgu yaparsınız, her güne veri ekler ve render edersiniz. Ayrı bir API uç noktası yok, JSON serileştirme sözleşmesi yok, istemcinin etkinlikleri almasını beklerken yükleme simgeleri yok.</li>
<li><strong>Bileşen test edilebilir.</strong> Tamamen PHP. Takvim mantığı, veri yükleyici ve render edilen çıktı, bir tarayıcı olmadan birim test edilebilir.</li>
</ul>
<hr/>
<h2>
<a name="phpcalendar-a-library-built-for-this" href="#phpcalendar-a-library-built-for-this"></a>
php-calendar: Bunun İçin İnşa Edilmiş Bir Kütüphane
</h2>
<p><code>tito10047/php-calendar</code>, Symfony ve Laravel için sunucu tarafı renderlama amacıyla baştan sona tasarlanmış saf bir PHP kütüphanesidir. Ön yüz bağımlılıkları yoktur. Şablonunuzun render etmesi için yapılandırılmış bir veri modeli üretir — ya yerleşik HTML rendereri ya da doğrudan Twig veya Blade ile.</p>
<p>Merkezi nesne <code>Calendar</code>, değiştirilemez bir değer nesnesidir. Her mutasyon — günlerin devre dışı bırakılması, verilerin yüklenmesi, aylar arası geçiş — yeni bir örnek döndürür. Bu, Live Components ile mükemmel bir şekilde uyumlu: her yeniden render, mevcut özelliklerden yeni bir <code>Calendar</code> oluşturur ve Symfony veya Laravel geri kalanını yönetir.</p>
<p>Kurulum:</p>
<div class="highlight js-code-highlight">
<pre class="highlight shell"><code>composer require tito10047/php-calendar<hr/>
<h2>
<a name="building-the-live-component" href="#building-the-live-component"></a>
Live Bileşeni İnşa Etmek
</h2>
<p>Gerçek bir uygulama burada. Takvim, Symfony UX Live Bileşeni olarak tasarlanmıştır. Tek bir <code>LiveProp</code> — mevcut tarih — yeniden render süreçlerinde hayatta kalır ve her etkileşimde sunucuya geri gönderilir.</p>
<div class="highlight js-code-highlight">
<pre class="highlight php"><code>#[AsLiveComponent('Forum:Scheduler:Calendar', template: 'Forum/Scheduler/Calendar.html.twig')]class Calendar
{
use DefaultActionTrait;
use ComponentToolsTrait;
private \Tito10047\Calendar\Calendar $calendar;
#[LiveProp()]
public \DateTimeImmutable $date;
public ?\DateTimeInterface $selectedDate = null;
public function __construct(private readonly CalendarDataReader $calendarDataReader) {}
#[PostMount]
public function postMount(): void
{
$this->date = $this->selectedDate ?? $this->date ?? new \DateTimeImmutable();
$this->postHydrate();
}
#[PostHydrate]
public function postHydrate(): void
{
$this->calendar = new \Tito10047\Calendar\Calendar(
date: $this->date,
daysGenerator: CalendarType::Monthly,
startDay: DayName::Monday,
dataLoader: $this->calendarDataReader,
);
}
public function getCurrentMonth(): \DateTimeInterface
{
return $this->calendar->getDate();
}
/ @return Day[][] */
public function getDays(): array
{
return $this->calendar->getDaysTable();
}
#[LiveAction]
public function nextMonth(): void
{
$this->calendar = $this->calendar->nextMonth();
$this->date = $this->calendar->getDate();
}
#[LiveAction]
public function prevMonth(): void
{
$this->calendar = $this->calendar->prevMonth();
$this->date = $this->calendar->getDate();
}
#[LiveAction]
public function select(#[LiveArg] string $date): void
{
$this->emit('daySelected', ['date' => $date]);
}
#[LiveAction]
public function today(): void
{
$this->date = new \DateTimeImmutable();
$this->postMount();
}}


