Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Rretzko's avatar
Level 15

NULL value on attach()

Hi - I can't figure out what is going wrong with this set up which is resulting in a null value being sent on an attach request. I have a school/student many-to-many relationship with these models

class School extends Model{
    
    public function students()
    {
        return $this->belongsToMany('App\Student', 'school_student', 'school_id', 'student_user_id');
    }
}

class Student extends Model 
{    
    protected $primaryKey = 'user_id';
 
    
    public function schools()
    {
        return $this->belongsToMany(School::class);
    }
}

and this Controller->store()

public function store(\App\Http\Requests\StudentAddSchoolStoreRequest $request)
    {
        $student = new Student();
        $student->id = auth()->user()->id;
        $school = new School();
  
        $school->id = $request->id;
        $student->schools()->attach($request->id);

        return redirect('school')->with('message', 'Successful update!');
    }

The attach command generates: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'student_user_id' cannot be null (SQL: insert into school_student (school_id, student_user_id) values (5320, ?))

However, it runs successfully if I substitute 'User' in place of Student

class User extends Authenticatable
{
    use Notifiable;

    public function schools()
    {
        return $this->belongsToMany(School::class,'school_student','school_id', 'student_user_id');
    }
}
public function store(\App\Http\Requests\StudentAddSchoolStoreRequest $request)
    {
        //StudentAddSchoolStoreRequest handles validation and error processing
        $user = new User();
        $user->id = auth()->user()->id;
        $school = new School();
  
        $school->id = $request->id;
        $user->schools()->attach($request->id);
        
        return redirect('school')->with('message', 'Successful update!');
    }

Any help seeing what I'm missing is appreciated!

0 likes
12 replies
Snapey's avatar

$this->belongsToMany should only be used when you have a pivot table.

For this a Student belongs to many schools and school belongs to many Student

Snapey's avatar

can you show your migrations for the three tables?

Rretzko's avatar
Level 15

Hi Snapey - Thanks. I am using a school_student (school_id, student_user_id) pivot table. Here are the migrations:

class CreateSchoolsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('schools', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('address_01');
            $table->string('address_02');
            $table->string('city');
            $table->integer('geo_states_id');
            $table->string('postal_code');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('schools');
    }
}

class CreateStudentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('students', function (Blueprint $table) {
            $table->unsignedBigInteger('user_id')->primary()
                    ->foreign('user_id')->references('id')->on('users')
                    ->onDelete('cascade');
            $table->integer('class_of');
            $table->integer('height')->default(30);
            $table->datetime('birthday')->nullable();
            $table->integer('shirt_size')->default(1)
                    ->foreign('shirt_size')->references('id')->on('shirt_sizes')
                    ->onDelete('cascade'); //Medium
            $table->integer('updated_by')->default(-1);
            $table->timestamps();
            $table->softDeletes();
            
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('students');
    }
}

class SchoolStudent extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::dropIfExists('school_student');
        
        Schema::create('school_student', function (Blueprint $table) {
            $table->unsignedBigInteger('school_id'); //user_id
            $table->unsignedBigInteger('student_user_id'); //user_id
            $table->unique(['school_id, student_user_id']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('school_student');
    }
}

Thanks for any additional help!

Snapey's avatar

You are not using incrementing ID on your students?

you should have public $incrementing=false; on your model?

Rretzko's avatar
Level 15

Hi Snapey - In my implementation are also users and Student is an extension of the User() model. I set the user_id as the primary key (i.e. protected $primaryKey = 'user_id' in Student()), which increments.

NicolasMica's avatar

👋 Hi there !

I think the problem is that you updated the default primaryKey property on you Student model.

protected $primaryKey = 'user_id';

However, Laravel uses that property to define which column name to use with relationships. Meaning when trying to attach the school to the student, it tries to store the user_id property of the Student model in the student_user_id column of you pivot table. But you stored the authenticated user's id inside the id property of the Student meaning you user_id property is null. At least that's my understanding of it.

$student = new Student();
$student->user_id = auth()->user()->id;

Hope it helps ! 🤞

Rretzko's avatar
Level 15

Hi Snapey - I replied to your questions regarding the pivot table, migrations and incrementing ID, but don't see any suggestions. Am I missing something here?

Rretzko's avatar
Level 15

Thanks Nicolas - So using your analysis and Snapey's, does this suggest that I:

  1. Setting an independent id for the Student() model and
  2. Include a foreign key reference to the user_id?
lprice's avatar

@rretzko You are creating/ newing up student and school models, but you don't save them to the database.

I would:

  1. Find or Create School, when created save it.
  2. Find or Create Student, and associate it with the School and save.
STEREOH's avatar
STEREOH
Best Answer
Level 18

You have this in your User model

    public function schools()
    {
        return $this->belongsToMany(School::class,'school_student','school_id', 'student_user_id');
    }

and this in your Student model

    public function schools()
    {
        return $this->belongsToMany(School::class);
    }

not tested but imo you should specify the keys for the relation as you do in your user model.

EDIT : Or maybe

public function store(\App\Http\Requests\StudentAddSchoolStoreRequest $request)
    {
        $student = new Student();
	// Replace id with user_id
        $student->user_id = auth()->user()->id;
        $school = new School();
  
        $school->id = $request->id;
        $student->schools()->attach($request->id);

        return redirect('school')->with('message', 'Successful update!');
    }
Rretzko's avatar
Level 15

Thanks Stereoh. My Users are teachers, students and parents, so the implementation of schools dependent on student_user_id in the User model won't work for my implementation. HOWEVER, when i edited the store() function to $student->student_user_id = auth()->user()->id; , this worked. I need to pull this apart to understand the 'why' , but thanks to all for the guidance!

Please or to participate in this conversation.