Error Handling
Diffyne provides automatic error handling with graceful fallbacks and user feedback.
Automatic Error Display
Validation Errors
Validation errors are automatically caught and displayed:
blade
<form diff:submit.prevent="submit">
<input diff:model.defer="email">
<span diff:error="email" class="text-red-500"></span>
<button type="submit">Submit</button>
</form>When validation fails, errors automatically appear in diff:error elements.
Server Errors
Server errors are caught and displayed via browser alert by default:
php
public function save()
{
// If this throws an exception
throw new \Exception('Something went wrong');
// User sees alert: "Something went wrong"
}Manual Error Handling
Add Custom Errors
php
public function checkAvailability()
{
if (!$this->isAvailable()) {
$this->addError('username', 'This username is already taken');
return;
}
// Continue...
}Reset Errors
php
public function clearErrors()
{
$this->resetValidation();
}
public function clearFieldError()
{
$this->resetValidation('email');
}Error Types
Diffyne handles different error types:
1. Validation Errors (422)
php
public function submit()
{
$this->validate(); // Throws ValidationException
// Errors automatically displayed in diff:error elements
}2. Server Errors (500)
php
public function process()
{
try {
// Risky operation
$this->processPayment();
} catch (\Exception $e) {
// Log error
logger()->error('Payment failed', [
'user' => auth()->id(),
'error' => $e->getMessage()
]);
// Show user-friendly message
$this->addError('general', 'Payment processing failed. Please try again.');
}
}3. Authorization Errors (403)
php
public function delete()
{
if (!auth()->user()->can('delete', $this->post)) {
$this->addError('general', 'You are not authorized to delete this post');
return;
}
$this->post->delete();
}Custom Error Messages
General Errors
blade
<div>
{{-- Show general errors --}}
@if($errors->has('general'))
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
{{ $errors->first('general') }}
</div>
@endif
{{-- Your component content --}}
</div>Component:
php
public function process()
{
if (!$this->canProcess()) {
$this->addError('general', 'Unable to process request');
return;
}
}Field-Specific Errors
blade
<div>
<input diff:model="email">
{{-- Automatic error display --}}
<span diff:error="email" class="text-red-500"></span>
{{-- Or manual display --}}
@error('email')
<span class="text-red-500">{{ $message }}</span>
@enderror
</div>Error Styling
Automatic Field Highlighting
Diffyne adds diffyne-error class to fields with errors:
css
/* Add to your CSS */
.diffyne-error {
border-color: #ef4444;
outline: none;
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}Manual Styling
blade
<input
diff:model="email"
class="border rounded px-3 py-2
@error('email') border-red-500 @enderror">Complete Error Handling Example
blade
<div class="max-w-md mx-auto">
{{-- General error message --}}
@if($errors->has('general'))
<div class="mb-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4" role="alert">
<p class="font-bold">Error</p>
<p>{{ $errors->first('general') }}</p>
</div>
@endif
{{-- Success message --}}
@if($success)
<div class="mb-4 bg-green-100 border-l-4 border-green-500 text-green-700 p-4" role="alert">
<p class="font-bold">Success</p>
<p>Your form was submitted successfully!</p>
</div>
@endif
<form diff:submit.prevent="submit">
{{-- Name field --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Name</label>
<input
type="text"
diff:model.defer="name"
class="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2">
<span diff:error="name" class="text-red-500 text-sm mt-1 block"></span>
</div>
{{-- Email field --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Email</label>
<input
type="email"
diff:model.defer="email"
class="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2">
<span diff:error="email" class="text-red-500 text-sm mt-1 block"></span>
</div>
{{-- Submit button --}}
<button
type="submit"
diff:loading.class="opacity-50 cursor-not-allowed"
diff:loading.attr="disabled"
class="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600">
<span diff:loading.remove>Submit</span>
<span diff:loading>Submitting...</span>
</button>
</form>
</div>Component:
php
<?php
namespace App\Diffyne;
use Diffyne\Component;
use Illuminate\Support\Facades\Mail;
class ContactForm extends Component
{
public string $name = '';
public string $email = '';
public bool $success = false;
protected function rules(): array
{
return [
'name' => 'required|min:3',
'email' => 'required|email',
];
}
protected function messages(): array
{
return [
'name.required' => 'Please enter your name',
'name.min' => 'Name must be at least 3 characters',
'email.required' => 'Please enter your email',
'email.email' => 'Please enter a valid email address',
];
}
public function submit()
{
try {
// Validate input
$validated = $this->validate();
// Check for additional business rules
if ($this->isBlacklisted($validated['email'])) {
$this->addError('email', 'This email address is not allowed');
return;
}
// Send email
Mail::to('admin@example.com')->send(new ContactMessage($validated));
// Show success
$this->success = true;
// Reset form
$this->reset('name', 'email');
$this->resetValidation();
} catch (\Illuminate\Validation\ValidationException $e) {
// Validation errors are automatically handled
throw $e;
} catch (\Exception $e) {
// Log unexpected errors
logger()->error('Contact form error', [
'user_input' => ['name' => $this->name, 'email' => $this->email],
'error' => $e->getMessage(),
]);
// Show user-friendly message
$this->addError('general', 'An error occurred. Please try again later.');
}
}
private function isBlacklisted(string $email): bool
{
return in_array($email, ['spam@example.com', 'blocked@example.com']);
}
}Error Recovery
Retry Logic
php
public function processPayment()
{
$attempts = 0;
$maxAttempts = 3;
while ($attempts < $maxAttempts) {
try {
$this->charge();
$this->success = true;
return;
} catch (\Exception $e) {
$attempts++;
if ($attempts >= $maxAttempts) {
$this->addError('general', 'Payment failed after multiple attempts');
logger()->error('Payment failed', ['error' => $e->getMessage()]);
return;
}
sleep(1); // Wait before retry
}
}
}Graceful Degradation
php
public function loadData()
{
try {
// Try primary data source
$this->data = $this->fetchFromApi();
} catch (\Exception $e) {
try {
// Fallback to cache
$this->data = Cache::get('data_backup');
$this->addError('general', 'Using cached data due to connection issues');
} catch (\Exception $e) {
// Final fallback
$this->data = [];
$this->addError('general', 'Unable to load data');
}
}
}Best Practices
1. Always Validate User Input
php
public function save()
{
// Always validate
$this->validate();
// Process data...
}2. Use Try-Catch for Risky Operations
php
public function process()
{
try {
// Risky operation
$this->externalApiCall();
} catch (\Exception $e) {
logger()->error('API call failed', ['error' => $e->getMessage()]);
$this->addError('general', 'Service temporarily unavailable');
}
}3. Provide User-Friendly Messages
php
// Good
$this->addError('email', 'This email is already registered');
// Avoid technical jargon
$this->addError('email', 'SQLSTATE[23000]: Integrity constraint violation');4. Log Errors for Debugging
php
try {
$this->process();
} catch (\Exception $e) {
// Log full error details
logger()->error('Processing failed', [
'component' => static::class,
'user' => auth()->id(),
'data' => $this->getState(),
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
// Show simple message to user
$this->addError('general', 'An error occurred');
}5. Reset Errors Appropriately
php
public function updated($field)
{
// Clear error for specific field when it changes
$this->resetValidation($field);
}
public function submit()
{
// Clear all errors before revalidating
$this->resetValidation();
$this->validate();
}Debugging
Enable Debug Mode
In config/diffyne.php:
php
return [
'debug' => env('DIFFYNE_DEBUG', false),
];Set in .env:
bash
DIFFYNE_DEBUG=trueCheck Browser Console
Open browser console (F12) to see:
- AJAX requests/responses
- Validation errors
- Server errors
- State changes
Server Logs
Check Laravel logs:
bash
tail -f storage/logs/laravel.logNext Steps
- Validation - Form validation details
- Forms - Form handling
- Testing - Test error scenarios
- Examples - Error handling examples
