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

Technical Evaluation

Architecture Fit

  • Pros:

    • Aligns with Laravel’s structured error handling by enforcing separation between public (user-facing) and private (debug) messages, reducing ad-hoc error responses.
    • Lightweight abstraction (~100 LOC) with zero framework lock-in, making it suitable for Laravel monoliths or standalone PHP projects.
    • HTTP status code support enables consistent API responses (e.g., 500 for server errors), integrating seamlessly with Laravel’s HttpException or JsonResponse.
    • Context-aware exceptions via ExceptionContext allow attaching metadata (e.g., IDs, timestamps) without bloating exception classes, improving debugging.
    • Backward-compatible: Can coexist with Laravel’s native exceptions (e.g., ValidationException) without conflicts.
  • Cons:

    • No built-in integration with Laravel’s Handler class or logging systems (e.g., Log::error()), requiring manual adaptation.
    • Lacks advanced features like localization, nested exceptions, or event hooks (e.g., throwing events in Symfony).
    • No middleware support: Cannot intercept exceptions globally (e.g., for analytics or rate limiting).
    • PHP 7.4+ requirement may exclude legacy Laravel 7.x projects without upgrades.

Integration Feasibility

  • Laravel Compatibility:

    • High: Works with Laravel’s exception hierarchy (e.g., throw new HttpException($e->getStatusCode(), $e->getDebugMessage())).
    • API-Friendly: Public messages can be serialized to JSON responses, while debug details are hidden in development.
    • No framework dependencies: Pure PHP, so it won’t conflict with Laravel’s service container or autoloading.
  • Migration Path:

    • Low Effort: Replace custom exceptions with BaseException in new code.
    • Moderate Effort: Retrofit existing exceptions to use ExceptionContext (requires constructor refactoring).
    • High Effort: Build a mixin/trait to backport functionality to legacy exceptions (e.g., trait UsesSimpleException).
  • Technical Risk:

    • Minimal: Package is stable (no breaking changes since 2021) and PHP 8 compatible.
    • Opportunity Risk: Overkill for projects with simple error handling or those using Laravel’s built-in exceptions.
    • Dependency Risk: Abandonware potential (0 stars, no maintainer). Mitigate by forking or rewriting the core logic.
    • Testing Risk: Ensure getDebugMessage() isn’t accidentally exposed in production (validate app()->debug()).

Key Questions

  1. Why adopt this over Laravel’s native exceptions?

    • Answer: If you need consistent public/private message separation across custom exceptions or standardized HTTP status codes for APIs.
    • Tradeoff: Laravel’s exceptions are sufficient for most use cases; this adds minimal value unless you’re building a large-scale system.
  2. How will this integrate with App\Exceptions\Handler?

    • Answer: Override render() or report() to check for BaseException and format responses/logs accordingly:
      public function render($request, Throwable $exception)
      {
          if ($exception instanceof BaseException) {
              return response()->json([
                  'message' => $exception->getPublicMessage(),
                  'errors' => $exception->getDebugMessage(), // Only in debug mode
              ], $exception->getStatusCode());
          }
          return parent::render($request, $exception);
      }
      
  3. Will this work with Laravel’s validation errors?

    • Answer: No—ValidationException is framework-specific. Use this package only for custom business exceptions.
  4. How will localization be handled?

    • Answer: Wrap messages in Laravel’s __() or build a decorator:
      $context = new ExceptionContext(
          __('errors.generic.user'), // Localized public message
          __('errors.generic.debug', ['id' => $id]), // Localized debug
          500
      );
      
  5. What’s the fallback if the package is abandoned?

    • Answer: Replace with a custom base exception or Laravel’s Exception class with similar properties:
      class CustomException extends \Exception
      {
          public function __construct(
              public string $publicMessage,
              public string $debugMessage,
              int $code = 0,
              ?\Throwable $previous = null
          ) {
              parent::__construct($debugMessage, $code, $previous);
          }
      }
      

Integration Approach

Stack Fit

  • Ideal Use Cases:

    • Laravel monoliths with complex business logic (e.g., SaaS, e-commerce) needing structured error responses.
    • APIs requiring consistent JSON error formats (public message + debug details in development).
    • Legacy codebases where exceptions lack metadata (e.g., missing IDs, timestamps).
    • Projects prioritizing consistency over framework-native solutions (e.g., avoiding Symfony’s ErrorHandler for simplicity).
  • Poor Fit:

    • Microservices: Overhead for lightweight services; prefer framework-native exceptions (e.g., Symfony\Component\HttpKernel\Exception\HttpException).
    • Simple CRUD apps: Laravel’s built-in exceptions (ValidationException, HttpException) are sufficient.
    • Projects using Symfony’s ErrorHandler: May duplicate functionality (e.g., ErrorHandler::render() already separates public/debug messages).

Migration Path

  1. Assessment Phase:

    • Audit existing exceptions: Identify which need public/private separation or HTTP status codes.
    • Decide on adoption scope:
      • Option A: Use only for new exceptions.
      • Option B: Retrofit all custom exceptions (higher effort).
      • Option C: Build a mixin/trait for legacy exceptions.
  2. Implementation:

    • Step 1: Install and Configure
      composer require holicz/simple-exception
      
    • Step 2: Create a Base Exception Class
      // app/Exceptions/BaseCustomException.php
      namespace App\Exceptions;
      
      use holicz\SimpleException\BaseException;
      use holicz\SimpleException\ExceptionContext;
      
      abstract class BaseCustomException extends BaseException
      {
          protected function createContext(string $public, string $debug, int $status): ExceptionContext
          {
              return new ExceptionContext($public, $debug, $status);
          }
      }
      
    • Step 3: Extend for Custom Exceptions
      // app/Exceptions/PaymentFailedException.php
      namespace App\Exceptions;
      
      class PaymentFailedException extends BaseCustomException
      {
          public function __construct(int $amount, string $gateway)
          {
              $context = $this->createContext(
                  'Payment failed. Please try again.',
                  sprintf('Gateway %s rejected amount %d: insufficient funds.', $gateway, $amount),
                  422
              );
              parent::__construct($context);
          }
      }
      
    • Step 4: Update App\Exceptions\Handler
      public function render($request, Throwable $exception)
      {
          if ($exception instanceof BaseCustomException) {
              return response()->json([
                  'message' => $exception->getPublicMessage(),
                  'debug'   => app()->debug() ? $exception->getDebugMessage() : null,
              ], $exception->getStatusCode());
          }
          return parent::render($request, $exception);
      }
      
    • Step 5: Test
      • Verify HTTP status codes (e.g., 422 for validation-like errors).
      • Check logging (ensure getDebugMessage() is captured by Log::error()).
      • Validate API responses for consistency (e.g., JSON structure).
  3. Advanced: Backport to Legacy Exceptions

    // app/Traits/UsesSimpleException.php
    trait UsesSimpleException
    {
        protected function getExceptionContext(string $public, string $debug, int $status): ExceptionContext
        {
            return new ExceptionContext($public, $debug, $status);
        }
    }
    
    // Legacy exception
    class LegacyException extends \Exception
    {
        use UsesSimpleException;
    
        public function __construct(int $id)
        {
            $context = $this->getExceptionContext(
                'Legacy error occurred.',
                sprintf('Failed to process ID %d.', $id),
                500
            );
            parent::__construct($context->getDebugMessage(), $context->getStatusCode());
        }
    
        public function getPublicMessage(): string
        {
            return $this->context->getPublicMessage();
        }
    }
    

Compatibility

  • PHP Versions: Supports 7.4–8.x (aligns with Laravel 8/9/10).
  • Laravel Versions: No hard dependencies, but **Laravel 8+
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.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
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