Installation
composer require chill-project/custom-fields
php artisan vendor:publish --provider="Chill\CustomFields\CustomFieldsServiceProvider" --tag="config"
php artisan migrate
Define a Custom Field
Edit config/custom-fields.php to add your first field group:
'groups' => [
'user_profile' => [
'label' => 'User Profile',
'fields' => [
'bio' => [
'type' => 'textarea',
'label' => 'Biography',
'required' => false,
],
'avatar' => [
'type' => 'file',
'label' => 'Avatar',
'upload_path' => 'uploads/avatars',
],
],
],
],
First Use Case
Attach fields to a model (e.g., User):
use Chill\CustomFields\Traits\HasCustomFields;
class User extends Authenticatable
{
use HasCustomFields;
protected $customFieldsGroup = 'user_profile';
}
Accessing Fields
$user = User::find(1);
$user->customField('bio'); // Returns "My bio text"
$user->setCustomField('bio', 'Updated bio');
$user->save();
Trait-Based Approach
Use HasCustomFields trait on any model to enable custom fields:
class Product extends Model
{
use HasCustomFields;
protected $customFieldsGroup = 'product_details';
}
Dynamic Group Assignment
Override getCustomFieldsGroup() for dynamic groups:
public function getCustomFieldsGroup()
{
return $this->type === 'premium' ? 'premium_fields' : 'standard_fields';
}
Validation Integrate with Laravel validation:
$validator = Validator::make($request->all(), [
'custom_field_bio' => 'required|max:500',
]);
Form Builder Integration
Use customFields() helper in Blade:
@foreach($user->customFields() as $field)
<div>
<label>{{ $field->label }}</label>
{!! $field->input($user->customField($field->name)) !!}
</div>
@endforeach
Bulk Updates
Use updateCustomFields() for mass updates:
User::where('role', 'admin')->updateCustomFields([
'bio' => 'Admin bio placeholder',
]);
Field Defaults Set defaults in config or via model boot:
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->setCustomField('last_active', now());
});
}
Resource Transformation
Extend JsonResource to include custom fields:
public function toArray($request)
{
return array_merge(parent::toArray($request), [
'custom_fields' => $this->customFields()->keyBy('name'),
]);
}
API Request Handling Parse incoming custom fields:
$data = $request->validate([
'custom_fields.*' => 'sometimes|string',
]);
$user->updateCustomFields($data['custom_fields'] ?? []);
Field Type Mismatches
file type field as text.type in config matches actual usage (e.g., handle file uploads separately).Missing Group Configuration
Undefined group 'user_profile' error.config/custom-fields.php and the model’s $customFieldsGroup matches.Case Sensitivity
strtolower() when referencing fields dynamically:
$user->customField(strtolower($fieldName));
Migration Conflicts
php artisan vendor:publish --tag="migrations" to customize the migration file.Field Existence Check
if ($user->hasCustomField('bio')) {
// Field exists
}
Raw Data Access For debugging, access the underlying data:
$user->getCustomFieldsData(); // Returns raw array
Event Listeners Listen for custom field changes:
CustomFieldUpdated::listen(function ($model, $fieldName, $oldValue, $newValue) {
Log::info("Field $fieldName updated from $oldValue to $newValue");
});
Custom Field Types Extend functionality by creating custom field types:
namespace App\CustomFields;
use Chill\CustomFields\FieldType;
class RichTextField extends FieldType
{
public function input($value = null)
{
return '<textarea>' . $value . '</textarea>';
}
}
Register in config/custom-fields.php:
'field_types' => [
'rich_text' => \App\CustomFields\RichTextField::class,
],
Validation Rules Add custom validation via service provider:
Validator::extend('custom_field_unique', function ($attribute, $value, $parameters, $validator) {
return !User::whereCustomField($parameters[0], $value)->exists();
});
Query Scoping
Use whereCustomField() for database queries:
$users = User::whereCustomField('bio', 'like', '%laravel%')->get();
Eager Loading Avoid N+1 queries:
$users = User::withCustomFields()->get();
Caching Cache custom fields for read-heavy applications:
$user->rememberCustomFieldsFor(3600); // Cache for 1 hour
How can I help you explore Laravel packages today?