<p><code>@throws</code> docbloğu trait ile beraber gider, böylece IDE'niz hâlâ ne tür istisnaları yükselteceğini bilir — ve doğrulama mantığı tam olarak bir yerde bulunur.</p>

<h3>
  <a name="step-4-catch-at-the-base-class-in-your-controller" href="#step-4-catch-at-the-base-class-in-your-controller">
  </a>
  Adım 4: Kontrolcünüzde Taban Sınıfında Yakalayın
</h3>

<p>Kontrolcü, <code>CheckInException</code>'ı — temel tür — yakalar ve bunu <code>ValidationException</code>'a dönüştürür. Herhangi bir bireysel istisna türü hakkında bilgi sahibi olmasına gerek yoktur. Her istisna, kendi anahtarını ve mesajını taşır:</p>

<div class="highlight js-code-highlight">
    <pre class="highlight php"><code><span class="c1">// app/Http/Controllers/CheckInController.php</span>

namespace App\Http\Controllers;

use App\Actions\CheckInAction;
use App\Exceptions\CheckInException;
use App\Http\Requests\CheckInRequest;
use App\Models\Booking;
use Illuminate\Validation\ValidationException;

class CheckInController
{
public function __invoke(CheckInRequest $request, Booking $booking, CheckInAction $action)
{
try {
$action->handle($booking, $request->seat_number);
} catch (CheckInException $e) {
throw ValidationException::withMessages([$e->getKey() => $e->getMessage()]);
}

    <span class="k">return</span> <span class="nf">response</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">json</span><span class="p">([</span><span class="s1>'message'</span> <span class="o">=&gt;</span> <span class="s1>'Check-in başarıyla gerçekleştirildi.'</span><span class="p">]);</span>
<span class="p">}</span>

}

<p>ValidationException'a dönüşümün güzelliği, front-end'in Laravel'in standart hata şeklini almasıdır:</p>

<div class="highlight js-code-highlight">
    <pre class="highlight json"><code><span class="p">{</span><span class="w">
        </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2> "Koltuğun 14A artık mevcut değil."</span><span class="p">,</span><span class="w">
        </span><span class="nl">"errors"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="nl">"seat_number"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2> "Koltuğun 14A artık mevcut değil."</span><span class="p">]</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
    </span></code></pre>
</div>

<p>Frontend'iniz büyük ihtimalle bununla nasıl başa çıkacağını zaten biliyor — bu, form isteği doğrulamasından üretilen aynı şekil. <code>seat_number</code> alanı vurgulanır, mesaj doğru yerde görünür ve ön tarafta özel bir şey ayarlamaya gerek kalmaz.</p>

<hr/>

<h2>
  <a name="the-payoff-other-callers-handle-what-they-care-about" href="#the-payoff-other-callers-handle-what-they-care-about">
  </a>
  Kazanç: Diğer Çağrılar, Önemsediği Şeylerle Baş Eder
</h2>

<p>İstisnalar düz domain nesneleri olduğundan, diğer tüm çağrılar onları kendi bağlamları için anlamlı bir şekilde ele alabilir.</p>

<p><strong>Bir sıraya alınmış iş</strong> belirli istisnaları yakalayarak yeniden deneme yapıp yapmayacağına karar verebilir:</p>

<div class="highlight js-code-highlight">
    <pre class="highlight php"><code><span class="k">public</span> <span class="k">function</span> <span class="n">handle</span><span class="p">(</span><span class="kt">CheckInAction</span> <span class="nv">$action</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
    <span class="k">try</span> <span class="p">{</span>
        <span class="nv">$action</span><span class="o">-&gt;</span><span class="nf">handle</span><span class="p">(</span><span class="nv">$this</span><span class="o">-&gt;</span><span class="n">booking</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="n">seatNumber</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nc">SeatUnavailableException</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1>// Farklı bir koltuk atamaya çalış</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="nf">reassignSeat</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nc">BoardingClosedException</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1>// Yeniden denemenin bir anlamı yok — temiz bir şekilde başarısız olur</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="nf">fail</span><span class="p">(</span><span class="nv">$e</span><span class="p">);</span>
    <span class="p">}</span>

}

<p><strong>Bir Filament eylemi</strong>, personeli çevrimiçi bildirim yapabilir, HTTP bağlantısı olmadan:</p>

<div class="highlight js-code-highlight">
    <pre class="highlight php"><code><span class="nc">Action</span><span class="o">::</span><span class="nf">make</span><span class="p">(</span><span class="s1>'checkIn'</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="nf">action</span><span class="p">(</span><span class="k">function</span> <span class="p">(</span><span class="kt">Booking</span> <span class="nv">$record</span><span class="p">)</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$action</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">try</span> <span class="p">{</span>
        <span class="nv">$action</span><span class="o">-&gt;</span><span class="nf">handle</span><span class="p">(</span><span class="nv">$record</span><span class="p">,</span> <span class="nv">$record</span><span class="o">-&gt;</span><span class="n">requested_seat</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nc">CheckInException</span> <span class="nv">$e</span><span class="p">)</span> <span class="p">{</span>
        <span class="nc">Notification</span><span class="o">::</span><span class="nf">make</span><span class="p">()</span>
            <span class="o">-&gt;</span><span class="nf">title</span><span class="p">(</span><span class="s1>'Check-in başarısız'</span><span class="p">)</span>
            <span class="o">-&gt;</span><span class="nf">body</span><span class="p">(</span><span class="nv">$e</span><span class="o">-&gt;</span><span class="nf">getMessage</span><span class="p">())</span>
            <span class="o">-&gt;</span><span class="nf">danger</span><span class="p">()</span>
            <span class="o">-&gt;</span><span class="nf">send</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">})</span>

<p><strong>Birim testi</strong> tam olarak nerede hata olduğunu doğrular:</p>

<div class="highlight js-code-highlight">
    <pre class="highlight php"><code><span class="k">public</span> <span class="k">function</span> <span class="n">test_cannot_check_in_twice</span><span class="p">():</span> <span class="kt">void</span>

{
$booking = Booking::factory()->checkedIn()->create();

<span class="nv">$this</span><span class="o">-&gt;</span><span class="nf">expectException</span><span class="p">(</span><span class="nc">AlreadyCheckedInException</span><span class="o">::</span><span class="n">class</span><span class="p">);</span>

<span class="p">(</span><span class="k">new</span> <span class="nc">CheckInAction</span><span class="p">)</span><span class="o">-&gt;</span><span class="nf">handle</span><span class="p">(</span><span class="nv">$booking</span><span class="p">,</span> <span class="s1>'14A'</span><span class="p">);</span>

}

<p>Bu çağrıların hiçbiri <code>HttpException</code> ya da durum kodları ile ilgilenmiyor. Onlar, bağlamlarının anladığı şekilde neyin yanlış gittiğini ele alıyor.</p>

<hr/>

<h2>
  <a name="why-not-just-use-the-global-exception-handler" href="#why-not-just-use-the-global-exception-handler">
  </a>
  Neden Sadece Global İstisna İşleyicisini Kullanmayalım?
</h2>

<p>Neden kontrolcünün yakalayıcı işlemi gerçekleştirdiğini merak ediyor olabilirsiniz, her şeyi <code>Handler.php</code>'de (veya Laravel 11+ 'da <code>bootstrap/app.php</code>'de) kayıt altına almak yerine. Her iki yaklaşım da çalışıyor, ancak kontrolcü yakalayıcısının bazı avantajları var:</p>

<p><strong>Yanıt formatı kararını lokal tutar.</strong> <code>ValidationException</code> formatı, bu uç nokta için kasıtlı bir seçimdir. Başka bir kontrolcü — örneğin bir iç panoda kullanılan — farklı bir yanıt biçimi isteyebilir. Eğer renderlemeyi handler'da merkezi hale getirirseniz, bu seçim global hale gelir.</p>

<p><strong><code>ValidationException</code> frontend ile ücretsiz uyum sağlar.</strong> Özel bir JSON yanıtı oluşturmak yerine, Laravel'in standart hata yapısını alırsınız ki çoğu frontend frameworkü ve doğrulama kütüphaneleri bunu zaten işler.</p>

<p><strong>Handler, çapraz kesim endişeleri için daha iyidir.</strong> Günlük kayıtları, Sentry'ye bildirim, genel bir 500 sayfası döndürme gibi işlemler global handler'da yer alır. Belirli bir uç noktanın domain hatalarını nasıl yüzeye çıkardığı, kontrolcü ile ilgilidir.</p>

<hr/>

<h2>
  <a name="summary" href="#summary">
  </a>
  Özete
</h2>

<div class="table-wrapper-paragraph"><table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Nereye Ait</th>
      <th>Olumsuz Yanlar</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>abort(422, '...')</code></td>
      <td>Hızlı kontrolcü kodu sadece</td>
      <td>İş mantığını HTTP'ye bağlar; kontrolcülerin dışına çıktığında bozulur</td>
    </tr>
    <tr>
      <td>Özel istisna + global işlemci</td>
      <td>Çapraz kesim HTTP renderleme</td>
      <td>Yanıt biçimi globaldir; uç noktalara göre varyasyonunu zorlaştırır</td>
    </tr>
    <tr>
      <td>Özel istisna + kontrolcü yakalayıcı → <code>ValidationException</code></td>
      <td>Kontrolcüler, işleri ve komutlardan çağrılan domain mantığı</td>
      <td>Biraz daha fazla kurulum, ama doğru endişe ayrımı</td>
    </tr>
  </tbody>
</table></div>

<p>Bu desen, iş mantığınız başka bir kontrolcü dışında çağrıldığında anında kazanç sağlar. Eylemleriniz temiz kalır, testleriniz kesinleşir ve frontend'iniz hiçbir özel kablolama olmadan tutarlı bir hata formatı alır — çünkü <code>ValidationException</code> zaten beklediği yapıdır.</p>

Kaynak: Orijinal Makale

Bu Makaleyi Paylaş