GitHub Repository

apiato

Definition

Exceptions are classes the handles errors, and helps developers debug their code in a more efficient way.

Principles

Rules

Folder Structure

 - App
    - Containers
        - {container-name}
            - Exceptions
                - AccountFailedException.php
                - ...

    - Ship
        - Exceptions
            - IncorrectIdException.php
            - InternalErrorException.php
            - ...

Code Samples

User Exception:

<?php

namespace App\Containers\User\Exceptions;

use App\Port\Exception\Abstracts\Exception;
use Symfony\Component\HttpFoundation\Response;

class AccountFailedException extends Exception
{
    public $httpStatusCode = Response::HTTP_CONFLICT;

    public $message = 'Failed creating new User.';
    
    public $code = 4711;
}

General Exception:

<?php

namespace App\Port\Exception\Exceptions;

use App\Port\Exception\Abstracts\Exception;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

class InternalErrorException extends Exception
{
    public $httpStatusCode = SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR;

    public $message = 'Something went wrong!';
}

General Exception with CustomData:

<?php

namespace App\Port\Exception\Exceptions;

use App\Port\Exception\Abstracts\Exception;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

class AwesomeExceptionWithCustomData extends Exception
{
    public $httpStatusCode = SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR;

    public $message = 'Something went wrong!';
    
    public $code = 1234;
    
    /*
     * Everything you add here will be automatically added to the ExceptionFormatter on the top level!
     * You can define any structure you want or maybe include translated messages
     */
    public function addCustomData() {
        return [
            'title' => 'nice',
            'description' => 'one fancy description here',
            'foo' => true,
            'meta' => [
                'bar' => 1234,
            ]
        ];
    }
}

Exception usage from anywhere:

<?php

throw new AccountFailedException();

Usage with Log for Debugging:

<?php

throw (new AccountFailedException())->debug($e); // debug() accepts string or \Exception instance

Usage and overriding the default message:

<?php

throw new AccountFailedException('I am the message to be displayed for the user');

Usage and overwriting pre-set CustomData

<?php

throw (new AwesomeExceptionWithCustomData())->overrideCustomData(['foo' => 'bar']);

Application Error Codes

Apiato provides a convenient way to manage all application error codes in one central place. Therefore, Apiato provides, amongst others, the \App\Ship\Exceptions\Codes\ApplicationErrorCodesTable class, which already holds various information for multiple errors.

Thereby, one error look like this:

const BASE_GENERAL_ERROR = [
	'code' => 1001,
	'title' => 'Unknown / Unspecified Error.',
	'description' => 'Something unexpected happened.',
];

Note that the code is used to be sent back to the client. The title and description, however, can be used to automatically generate a documentation regarding all defined error codes and their meaning. Please note that this feature is currently not implemented but will be added later on.

Linking Exceptions and Error Codes

In order to link an error code to an Exception, you simply need override the useErrorCode() method of the Exception.

Consider the following example:

class InternalErrorException extends Exception
{

    public $httpStatusCode = SymfonyResponse::HTTP_INTERNAL_SERVER_ERROR;

    public $message = 'Something went wrong!';
	
	public code = 4711; // this code will be overwritten by the useErrorCode() method!

    public function useErrorCode()
    {
        return ApplicationErrorCodes::BASE_INTERNAL_ERROR;
    }
}

Please note that already defined $code values may be overwritten by the useErrorCode() method! Furthermore, this feature is completely optional - you may still use the known public $code = 4711; approach to manually set an error code.

Defining Own Error Code Tables

Of course, Apiato allows you to define your own CustomErrorCodesTable. In fact, there already exists such a file where you can define your own error codes. Please note that the ApplicationErrorCodesTable may be adapted by Apiato - the others will not.

If you like to split the errors in various files, you can easily create a UserErrorCodesTable in respective namespace and define the errors accordingly. However, you need to manually “register” this code table. This can be achieved in the ErrorCodeManager::getCodeTables() method.

Now you can easily use your UserErrorCodesTable::USER_NOT_VERIFIED error in your Exception class.