Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Simple Exception Laravel Package

holicz/simple-exception

Lightweight base exception for PHP/Laravel with structured context: a safe public message for users, a private debug message for logs, and an HTTP status code. Create your own exceptions by extending BaseException and pass an ExceptionContext.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by installing the package via Composer:

composer require holicz/simple-exception

First Use Case: Create a custom exception for a business-specific error (e.g., CouldNotRemoveArticleException) to standardize error handling in your Laravel application.

Example:

// app/Exceptions/CouldNotRemoveArticleException.php
namespace App\Exceptions;

use holicz\SimpleException\BaseException;
use holicz\SimpleException\ExceptionContext;

class CouldNotRemoveArticleException extends BaseException
{
    public function __construct(int $articleId)
    {
        $exceptionContext = new ExceptionContext(
            'Failed to remove the article. Please try again.',
            sprintf('Article with ID %d could not be deleted due to a database constraint.', $articleId),
            422 // HTTP status code
        );
        parent::__construct($exceptionContext);
    }
}

Where to Look First:

  • Review the BaseException and ExceptionContext classes in vendor/holicz/simple-exception/src/ to understand the structure.
  • Check the App\Exceptions\Handler in Laravel to see how to integrate the custom exception into your error-handling pipeline.

Implementation Patterns

Usage Patterns

  1. Extending BaseException: Always extend BaseException for custom exceptions. Pass an ExceptionContext object in the constructor to define the public message, debug message, and HTTP status code.

    class PaymentFailedException extends BaseException
    {
        public function __construct(string $paymentId, string $error)
        {
            $context = new ExceptionContext(
                'Payment processing failed. Please contact support.',
                "Payment ID: {$paymentId}. Error: {$error}",
                402 // HTTP status code
            );
            parent::__construct($context);
        }
    }
    
  2. Handling Exceptions: Catch exceptions and use the provided methods to access messages and status codes.

    try {
        // Business logic that may throw an exception
    } catch (CouldNotRemoveArticleException $e) {
        return response()->json([
            'message' => $e->getPublicMessage(),
            'debug' => app()->debug() ? $e->getDebugMessage() : null,
        ], $e->getStatusCode());
    }
    
  3. Logging: Use getDebugMessage() for logging detailed error information.

    catch (PaymentFailedException $e) {
        Log::error($e->getDebugMessage(), [
            'context' => 'payment_processing',
            'payment_id' => $paymentId,
        ]);
        return response()->json(['error' => $e->getPublicMessage()], $e->getStatusCode());
    }
    

Workflow Integration

  1. API Responses: Standardize API error responses using BaseException in App\Exceptions\Handler.

    public function render($request, Throwable $exception)
    {
        if ($exception instanceof BaseException) {
            return response()->json([
                'error' => $exception->getPublicMessage(),
                'debug' => app()->debug() ? $exception->getDebugMessage() : null,
            ], $exception->getStatusCode());
        }
        return parent::render($request, $exception);
    }
    
  2. Validation Errors: Extend BaseException for validation errors to maintain consistency.

    class ValidationException extends BaseException
    {
        public function __construct(array $errors)
        {
            $context = new ExceptionContext(
                'Validation failed. Please correct the errors below.',
                json_encode($errors),
                422
            );
            parent::__construct($context);
        }
    }
    
  3. Middleware for Debugging: Use middleware to log exceptions with debug messages in development.

    public function handle($request, Closure $next)
    {
        try {
            return $next($request);
        } catch (BaseException $e) {
            Log::debug($e->getDebugMessage());
            throw $e;
        }
    }
    

Laravel-Specific Tips

  • Use with Laravel’s HTTP Exceptions: Convert BaseException to Laravel’s HttpResponseException for seamless integration.

    catch (BaseException $e) {
        throw new HttpResponseException(
            response()->json([
                'error' => $e->getPublicMessage(),
                'debug' => app()->debug() ? $e->getDebugMessage() : null,
            ], $e->getStatusCode())
        );
    }
    
  • Localization: Wrap public messages in Laravel’s __() function for multilingual support.

    $context = new ExceptionContext(
        __('errors.payment_failed'),
        "Payment ID: {$paymentId}. Error: {$error}",
        402
    );
    

Gotchas and Tips

Pitfalls

  1. Inconsistent Adoption:

    • If not all exceptions extend BaseException, error responses will be inconsistent.
    • Fix: Enforce via static analysis tools (e.g., PHPStan) or documentation.
  2. Debug Messages Leaking:

    • Accidentally exposing getDebugMessage() to end-users in production.
    • Fix: Always check app()->debug() before exposing debug details.
    return response()->json([
        'error' => $e->getPublicMessage(),
        'debug' => app()->debug() ? $e->getDebugMessage() : null,
    ]);
    
  3. HTTP Status Code Mismatch:

    • Using incorrect HTTP status codes (e.g., 500 for client errors).
    • Fix: Document standard status codes for each exception type (e.g., 422 for validation, 500 for server errors).
  4. Overhead in Simple Projects:

    • Unnecessary complexity for small projects with minimal error handling.
    • Fix: Evaluate if the package adds value or if Laravel’s built-in exceptions suffice.

Debugging Tips

  1. Logging Context: Log the full ExceptionContext for debugging complex issues.

    Log::error('Exception occurred', [
        'public_message' => $e->getPublicMessage(),
        'debug_message' => $e->getDebugMessage(),
        'status_code' => $e->getStatusCode(),
        'context' => $e->getContext(), // If extended
    ]);
    
  2. Testing Exceptions: Write unit tests to verify public/debug message separation and status codes.

    public function test_exception_messages()
    {
        $exception = new CouldNotRemoveArticleException(1);
        $this->assertEquals('Failed to remove the article. Please try again.', $exception->getPublicMessage());
        $this->assertEquals(422, $exception->getStatusCode());
    }
    
  3. Extending ExceptionContext: Add custom properties to ExceptionContext for additional metadata (e.g., timestamps, user IDs).

    $context = new ExceptionContext(
        'User not found.',
        'User with ID 123 does not exist.',
        404,
        ['user_id' => 123, 'timestamp' => now()]
    );
    

    Then extend BaseException to support the new property:

    class BaseException extends \Exception
    {
        protected $context;
    
        public function getContext(): array
        {
            return $this->context['extra'] ?? [];
        }
    }
    

Configuration Quirks

  1. No Built-in Localization: The package does not support localization out of the box. Use Laravel’s __() function or a decorator pattern.

    $context = new ExceptionContext(
        __('errors.generic_error'),
        $debugMessage,
        500
    );
    
  2. No Event Dispatching: The package does not integrate with Laravel’s event system. Manually dispatch events if needed.

    catch (BaseException $e) {
        event(new ExceptionOccurred($e));
        throw $e;
    }
    
  3. PHP Version Compatibility: Ensure your project uses PHP 7.4+ (or PHP 8) to avoid compatibility issues.

Extension Points

  1. Custom ExceptionContext: Extend ExceptionContext to add domain-specific properties.

    class CustomExceptionContext extends ExceptionContext
    {
        public function __construct(
            string $publicMessage,
            string $debugMessage,
            int $statusCode,
            public array $metadata
        ) {
            parent::__construct($publicMessage, $debugMessage, $statusCode);
        }
    }
    
  2. Exception Handlers: Create a base handler for all BaseException instances in App\Exceptions\Handler.

    public function render($request, BaseException $exception)
    {
        return response()->json([
            'error' => $exception->getPublicMessage(),
            'debug' => app()->debug() ? $exception->getDebugMessage() : null,
            'code' => $exception->getStatusCode(),
        ], $exception->getStatusCode());
    }
    
  3. Middleware for Global Handling: Use middleware to catch and log exceptions globally.

    public function handle($request
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed