Skip to content

API controller ​

A complete CRUD controller for a model with custom fields.

Request ​

php
use Illuminate\Foundation\Http\FormRequest;

class SaveUserRequest extends FormRequest
{
    public function rules(): array
    {
        $user = $this->route('user') ?? new User;

        return [
            'name' => ['required', 'string'],
            'email' => ['required', 'email'],
            ...$user->customFieldRules(),
        ];
    }
}

Controller ​

php
class UserController
{
    public function index()
    {
        return User::withCustomFields()
            ->when(request('tax_bracket'), fn ($q, $value) => $q->whereCustomField('tax_bracket', $value))
            ->paginate();
    }

    public function store(SaveUserRequest $request)
    {
        return User::create($request->validated());       // 201 includes the custom fields
    }

    public function show(User $user)
    {
        return $user->load('customFieldValues');
    }

    public function update(SaveUserRequest $request, User $user)
    {
        $user->update($request->validated());

        return $user->load('customFieldValues');
    }

    public function destroy(User $user)
    {
        $user->delete();                                  // deletes the values too

        return response()->noContent();
    }
}

Behavior ​

  • A missing required field or an invalid value returns a normal 422, next to the errors for your columns.
  • Keys without a rule are left out of validated(), so they never reach the model.
  • load('customFieldValues') loads the values, so the response includes the custom fields.

Test ​

php
public function test_it_stores_custom_fields(): void
{
    CustomFields::create([
        'model' => User::class,
        'key' => 'tax_bracket',
        'label' => 'Tax bracket',
        'type' => 'select',
        'settings' => ['options' => ['a' => 'A', 'b' => 'B']],
    ]);

    $this->postJson('/users', ['name' => 'Ken', 'email' => 'ken@example.com', 'tax_bracket' => 'b'])
        ->assertCreated()
        ->assertJsonPath('tax_bracket', 'b');

    $this->postJson('/users', ['name' => 'Ken', 'email' => 'ken@example.com', 'tax_bracket' => 'z'])
        ->assertUnprocessable()
        ->assertJsonValidationErrors('tax_bracket');
}

Released under the MIT License.