›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-custom-fields
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Defining fields
  • Field types and storage
  • Tenant scoping
  • Reading and writing values
  • Validation
  • Filtering records

Operations

  • Changing and deleting fields
  • Queries and eager loading
  • Events and listeners

Reference

  • Configuration
  • Console commands
  • Exceptions
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • Defining fields
  • Field types and storage
  • Tenant scoping
  • Reading and writing values
  • Validation
  • Filtering records

Operations

  • Changing and deleting fields
  • Queries and eager loading
  • Events and listeners

Reference

  • Configuration
  • Console commands
  • Exceptions
  • Testing
  • Troubleshooting

byrcsc/laravel-custom-fields · 1.x

Exceptions.

Every exception the package throws, what triggers it, and which layer it comes from.

The package fails loudly. A key it does not recognise, a value it cannot store, and a filter it cannot compile portably all throw rather than returning null or an empty result, because each of those would be found much later.

The list

ExceptionExtendsThrown when
InvalidDefinitionExceptionInvalidArgumentExceptiondefine() was given something it cannot honour
InvalidValueExceptionInvalidArgumentExceptionA value cannot be stored as, or read back as, the field's type
InvalidTenantResolverExceptionInvalidArgumentExceptioncustom-fields.tenant_resolver is not a resolver
UnknownCustomFieldExceptionRuntimeExceptionThe current tenant has no such field on that model
UnsavedModelExceptionRuntimeExceptionA write against a record that has never been saved
UnfilterableFieldExceptionRuntimeExceptionA filter the package will not compile
CannotChangeFieldTypeExceptionRuntimeExceptionA type change on a definition that already has values

All of them live in ByRcsc\LaravelCustomFields\Exceptions.

There is no shared package base class. Each one extends an SPL exception directly, so there is no single catch that covers the package and nothing else. Catch the specific class you mean, or InvalidArgumentException and RuntimeException if you need both halves.

Two more come from outside the package and are worth knowing here. Illuminate\Validation\ValidationException is what a failed rule throws, on a form and on a write. Illuminate\Database\Eloquent\MassAssignmentException is what writing a definition or a value around the facade throws, because both models guard every attribute.

Configuration and development errors

These fire against code you are holding in your head, so every message names the field and says what would have been acceptable.

InvalidDefinitionException

Everything define() refuses:

  • An unknown type, or none: Unknown custom field type [file]. Use one of: text, textarea, ...
  • A key that is missing, empty, or outside the pattern.
  • A key already defined on that model for that tenant.
  • A select or multi_select with no options, or options on a type that has none, or an options list that is not strings.
  • An attribute name it does not recognise.
  • A rule name it will never run, or a rule setting it cannot honour.
  • unique on a multi_select or json.
  • A sort_order that is not a whole number.
  • A tenant that is neither null nor a non-empty string.
  • A first argument that is not an Eloquent model class.

InvalidTenantResolverException

The configured resolver is missing, is not a class, or does not implement TenantResolver. It is thrown the first time the resolver is needed rather than at boot, so the application still boots and the failure names the config key instead of arriving as a container error from three frames down.

Runtime errors

UnknownCustomFieldException

A key that is not defined for the model under the tenant currently being acted for. Thrown by getCustomField(), setCustomField(), setCustomFields(), and both filter scopes.

No custom field [account_tier] is defined on [App\Models\Customer] while the current
tenant is [globex].

The message says which tenant was current, because the same key is often defined for a different one. CustomFields::definition() is the read path that answers null instead, which makes it the way to ask whether a field exists.

UnsavedModelException

A write against a record with no key yet. Values are stored against the record's key, so save it first.

InvalidValueException

The type layer, not the rules layer. An array handed to a text field, an unparseable date, a bare string handed to a multi_select, a value with no JSON form.

It also covers the read direction: a stored row whose column does not hold what its field's type says it should throws rather than coming back as null. That is only reachable by writing the values table around the trait, which is exactly the case worth hearing about rather than papering over.

With validate_on_write on, most wrong-typed values are reported as validation failures first, because the rules run before the type layer. Turning validation off does not turn this off. See type errors are not validation errors.

UnfilterableFieldException

A filter the package refuses to compile, because no answer it could give would be the same answer on every supported engine. Three cases:

  • Equality on a json field.
  • whereCustomField() on a multi_select given a list rather than one option.
  • whereCustomFieldIn() on a multi_select or a json field.

See filtering records.

CannotChangeFieldTypeException

A type change on a definition with values behind it. The message names the field, both types, and how many values are in the way. See changing and deleting fields.

Handling them

Most of these are developer errors and should reach your error tracker rather than a catch. Three are worth handling:

use ByRcsc\LaravelCustomFields\Exceptions\UnknownCustomFieldException;
use Illuminate\Validation\ValidationException;

try {
    $customer->setCustomFields($request->validated()['custom_fields'] ?? []);
} catch (UnknownCustomFieldException) {
    // a key the tenant's field set no longer has
} catch (ValidationException $exception) {
    // a value that broke a rule
}

UnknownCustomFieldException is the one that fires on input rather than on code, because a form can be posted after the field behind it was deleted. CannotChangeFieldTypeException is worth catching in an admin screen that lets a tenant edit its own fields, so the refusal reads as a message rather than a 500.

What to read next

  • Validation for the rules layer and what it throws.
  • Field types and storage for the type layer underneath it.
  • Troubleshooting for what to check when one of these fires.
PreviousConsole commandsNextTesting
View source

On this page

  1. The list
  2. Configuration and development errors
  3. InvalidDefinitionException
  4. InvalidTenantResolverException
  5. Runtime errors
  6. UnknownCustomFieldException
  7. UnsavedModelException
  8. InvalidValueException
  9. UnfilterableFieldException
  10. CannotChangeFieldTypeException
  11. Handling them
  12. What to read next