CustomFieldRegistry
The CustomFieldRegistry class holds and manages all available custom field type instances at runtime. It provides a single source of truth for resolving field implementations by their unique type.
Namespace
JobMetric\CustomField\Support\CustomFieldRegistry
Overview
The registry acts as an in-memory catalog for all registered fields. It ensures each field type is unique and provides predictable lookups for field instances. This is essential for the package's extensibility, allowing you to register custom field types that can be used throughout your application.
Available Methods
Register
Register a field instance by its type:
$registry->register(FieldContract $field): static
Parameters:
$field(FieldContract): The field instance to be registered. Itstype()must be unique.
Returns: static - Returns the registry instance for method chaining.
Throws: InvalidArgumentException - If a field with the same type is already registered.
Example:
use JobMetric\CustomField\Support\CustomFieldRegistry;
use JobMetric\CustomField\Contracts\FieldContract;
$registry = app('CustomFieldRegistry');
$customField = new MyCustomField();
$registry->register($customField);
Get
Resolve and return a field instance by its type:
$registry->get(string $type): FieldContract
Parameters:
$type(string): The unique type of the field (e.g., "text", "color").
Returns: FieldContract - The corresponding field instance.
Throws: InvalidArgumentException - If the type has not been registered.
Example:
$textField = $registry->get('text');
All
Return all registered field instances indexed by their types:
$registry->all(): array
Returns: array<string, FieldContract> - Map of type => field instance.
Example:
$allFields = $registry->all();
// Returns: [
// 'text' => TextField instance,
// 'select' => SelectField instance,
// ...
// ]
Complete Examples
Register Custom Field Type
use JobMetric\CustomField\Support\CustomFieldRegistry;
use JobMetric\CustomField\Contracts\FieldContract;
use JobMetric\CustomField\Core\BaseCustomField;
class CustomTextField extends BaseCustomField implements FieldContract
{
public static function type(): string
{
return 'custom-text';
}
// ... implementation
}
// Register in service provider
$registry = app('CustomFieldRegistry');
$registry->register(new CustomTextField());
List All Available Field Types
$registry = app('CustomFieldRegistry');
$allFields = $registry->all();
foreach ($allFields as $type => $field) {
echo "Field type: {$type}\n";
echo "Class: " . get_class($field) . "\n";
}
Registering Custom Fields
To use a custom field in your application, you must register it with the CustomFieldRegistry. Registration typically happens in a service provider's boot() method, ensuring fields are available when the application starts.
Registration Process
The registration process involves:
- Creating the Field Class: Create a custom field class that extends
BaseCustomFieldand implementsFieldContract - Defining the Type: Implement the
type()method to return a unique field type identifier - Registering in Service Provider: Register the field instance in a service provider's
boot()method - Automatic Initialization: The package automatically initializes registered fields, registering Blade namespaces and making them available through
CustomFieldBuilder
Step-by-Step Registration
Step 1: Create Your Custom Field
First, create your custom field class:
<?php
namespace App\CustomFields\ColorPicker;
use JobMetric\CustomField\Contracts\FieldContract;
use JobMetric\CustomField\Core\BaseCustomField;
class ColorPicker extends BaseCustomField implements FieldContract
{
/**
* Get the type of the field.
*
* @return string
*/
public static function type(): string
{
return 'color-picker';
}
}
Or use the custom-field:make command:
php artisan custom-field:make ColorPicker
Step 2: Register in Service Provider
Register your custom field in a service provider. You can use AppServiceProvider or create a dedicated service provider.
Option 1: Using AppServiceProvider
<?php
namespace App\Providers;
use App\CustomFields\ColorPicker;
use Illuminate\Support\ServiceProvider;
use JobMetric\CustomField\Support\CustomFieldRegistry;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
$registry = app('CustomFieldRegistry');
// Register your custom field
$registry->register(new ColorPicker);
}
}
Option 2: Creating a Dedicated Service Provider
Create a dedicated service provider for custom fields:
php artisan make:provider CustomFieldServiceProvider
<?php
namespace App\Providers;
use App\CustomFields\ColorPicker;
use App\CustomFields\RichTextEditor;
use App\CustomFields\FileUpload;
use Illuminate\Support\ServiceProvider;
use JobMetric\CustomField\Support\CustomFieldRegistry;
class CustomFieldServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register(): void
{
//
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
$registry = app('CustomFieldRegistry');
// Register all custom fields
$registry->register(new ColorPicker);
$registry->register(new RichTextEditor);
$registry->register(new FileUpload);
}
}
Don't forget to register the service provider in config/app.php:
'providers' => [
// ...
App\Providers\CustomFieldServiceProvider::class,
],
Step 3: Automatic Initialization
Once registered, the package automatically:
- Registers Blade Namespace: Creates a namespace for your field's views (e.g.,
custom-field-color-picker) - Initializes the Field: Calls the
init()method which registers the field as a macro onCustomFieldBuilder - Makes Available in Builder: Your field becomes available through
CustomFieldBuilder::colorPicker()
Complete Registration Example
Here's a complete example of registering multiple custom fields:
<?php
namespace App\Providers;
use App\CustomFields\ColorPicker;
use App\CustomFields\RichTextEditor;
use App\CustomFields\DateRangePicker;
use App\CustomFields\FileUpload;
use Illuminate\Support\ServiceProvider;
use JobMetric\CustomField\Support\CustomFieldRegistry;
class CustomFieldServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* @return void
*/
public function boot(): void
{
$registry = app('CustomFieldRegistry');
// Register custom fields
$this->registerCustomFields($registry);
}
/**
* Register all custom fields.
*
* @param CustomFieldRegistry $registry
* @return void
*/
protected function registerCustomFields(CustomFieldRegistry $registry): void
{
$fields = [
new ColorPicker,
new RichTextEditor,
new DateRangePicker,
new FileUpload,
];
foreach ($fields as $field) {
$registry->register($field);
}
}
}
Using Registered Fields
After registration, use your custom fields through CustomFieldBuilder:
use JobMetric\CustomField\CustomFieldBuilder;
// Your custom field is now available
$field = CustomFieldBuilder::colorPicker()
->name('theme_color')
->label('Theme Color')
->value('#3498db')
->build();
$html = $field->toHtml();
Registration Timing
Important: Fields must be registered in the boot() method, not register(). This is because:
- The registry service is registered as a singleton in the
register()phase - Field initialization requires the application to be fully booted
- Blade namespaces are registered during the boot phase
Correct:
public function boot(): void
{
$registry = app('CustomFieldRegistry');
$registry->register(new ColorPicker);
}
Incorrect:
public function register(): void
{
// ❌ Too early - registry may not be available
$registry = app('CustomFieldRegistry');
$registry->register(new ColorPicker);
}
Registration Order
The order of registration matters if fields depend on each other. Register base fields before dependent fields:
public function boot(): void
{
$registry = app('CustomFieldRegistry');
// Register base fields first
$registry->register(new BaseField);
// Then register fields that extend base fields
$registry->register(new ExtendedField);
}
Error Handling
Duplicate Type Registration
If you try to register a field with a type that's already registered:
$registry->register(new ColorPicker); // type: 'color-picker'
$registry->register(new AnotherColorPicker); // type: 'color-picker' - ERROR!
Error:
InvalidArgumentException: Field type 'color-picker' already registered.
Solution: Ensure each field has a unique type identifier.
Missing View Directory
If your field doesn't have a views directory:
Error:
BladeViewNotFoundException: View directory not found
Solution: Ensure your field has a views directory with at least a default.blade.php file:
app/CustomFields/ColorPicker/
├── ColorPicker.php
└── views/
└── default.blade.php
Best Practices for Registration
-
Use Dedicated Service Provider: Create a separate service provider for custom fields to keep code organized
-
Group Related Fields: Register related fields together for better organization
-
Document Field Types: Document your custom field types for team members
-
Validate Before Registration: Ensure fields are properly configured before registration
-
Handle Errors Gracefully: Wrap registration in try-catch blocks if needed
public function boot(): void
{
$registry = app('CustomFieldRegistry');
try {
$registry->register(new ColorPicker);
} catch (\InvalidArgumentException $e) {
\Log::error('Failed to register ColorPicker: ' . $e->getMessage());
}
}
- Use Conditional Registration: Register fields conditionally based on environment or configuration
public function boot(): void
{
$registry = app('CustomFieldRegistry');
if (config('app.enable_advanced_fields')) {
$registry->register(new AdvancedField);
}
}
Package Integration
If you're developing a package that provides custom fields, register them in your package's service provider:
<?php
namespace YourPackage\Providers;
use Illuminate\Support\ServiceProvider;
use JobMetric\CustomField\Support\CustomFieldRegistry;
use YourPackage\CustomFields\PackageField;
class YourPackageServiceProvider extends ServiceProvider
{
public function boot(): void
{
$registry = app('CustomFieldRegistry');
$registry->register(new PackageField);
}
}
When to Use CustomFieldRegistry
Use the registry when you need to:
- Register Custom Field Types: Add new field types to the system
- Introspect Available Fields: List all available field types for UI pickers or documentation
- Resolve Field Instances: Get field instances by type for dynamic field creation
- Ensure Type Uniqueness: Prevent duplicate field type registrations