phplaraveleloquentlaravel-nova

Laravel Nova: How to Create User and Associated Profile Simultaneously in One Step


I'm working on a Laravel project with Nova 4 and I'm struggling to create a User with the role 'instructor' and their associated InstructorProfile in a single step using Nova's admin interface. It's crucial that both records are created simultaneously, not in separate steps.

Current Setup

User Migration:

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('firstName');
    $table->string('surname');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->enum('role', ['admin', 'instructor', 'normal'])->default('normal');
    $table->index('email');
    $table->index('role');
    $table->rememberToken();
    $table->timestamps();
});

InstructorProfile Migration:

Schema::create('instructor_profiles', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->onDelete('cascade');
    $table->string('phoneNumber')->nullable();
    $table->text('bio')->nullable();
    $table->text('qualifications')->nullable();
    $table->string('photo')->nullable();
    $table->timestamps();
});

What I've Tried

I've attempted to override the fill() method in my Nova resource:


class InstructorProfile extends Resource
{
    public static $model = \App\Models\User::class;

    public static $title = 'firstName';

    public static $search = [
        'id', 'user.firstName', 'user.surname', 'user.email',
    ];

    public static function indexQuery(NovaRequest $request, $query)
    {
        return $query->where('role', 'instructor');
    }

    public static $with = ['instructorProfile'];



    public function fields(NovaRequest $request)
    {
        return [
            ID::make()->sortable(),

            Text::make('First Name', 'firstName')
                ->sortable()
                ->rules('required', 'max:255'),

            Text::make('Surname')
                ->sortable()
                ->rules('required', 'max:255'),

            Email::make('Email')
                ->sortable()
                ->rules('required', 'email', 'max:254')
                ->creationRules('unique:users,email')
                ->updateRules('unique:users,email,{{resourceId}}'),

            Password::make('Password')
                ->onlyOnForms()
                ->creationRules('required', 'string', 'min:8')
                ->updateRules('nullable', 'string', 'min:8'),

            Hidden::make('Role')
                ->default('instructor'),

            Text::make('Phone Number',"instructor.phoneNumber") ,

            Textarea::make('Bio',"instructor.bio")
                ->nullable()
                ->hideFromIndex(),

            Textarea::make('Qualifications',"instructor.qualifications")
                ->nullable()
                ->hideFromIndex(),

            Image::make('Photo',"instructor.photo")
                ->disk('public')
                ->path('instructor-photos')
                ->prunable()
                ->deletable(),
        ];
    }

    public static function fill(NovaRequest $request, $model)
    {
        $model =  parent::fill($request, $model);

        $model->instructorProfile()->create([
            'created_by' => auth()->id(),
            'bio' => $request->instructor_bio,
            'phoneNumber' => $request->instructor_phoneNumber,
            'qualifications' => $request->instructor_qualifications
        ]);

         return $model;
    }

However, this doesn't work because $model doesn't seems even User in this case and it's just an array.

How can I modify my Nova resource to create both the User and InstructorProfile records in a single operation when using Nova's admin interface?

Environment

I need a way to create both records simultaneously within Nova and never in two steps or two resources.


Solution

  • Try using the HasOne field, this should allow you to create an Instructor Profile when creating the Instructor

    use Laravel\Nova\Fields\HasOne;
    
    HasOne::make('Instructor Profile'),