Save Relationship 1:1 on Laravel 5.3

Asked

Viewed 1,002 times

4

In my scenario, I have tables of users and teachers, where a teacher has a user, so I have a relationship 1:1.

Migrations:

create_users_table

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name', 150);
    $table->string('username', 20)->unique();
    $table->string('email', 100)->unique();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

create_teachers_table

Schema::create('teachers', function (Blueprint $table) {
    $table->increments('id');
    $table->date('birth');
    $table->string('about');
    $table->integer('user')->unsigned();
    $table->foreign('user')->references('id')->on('users');
    $table->timestamps();
});

Models:

User

protected $fillable = [
    'username', 'email', 'password', 'name', 'remember_token',
];


protected $hidden = [
    'password', 'remember_token'
];


public function teacher() {
    return $this->belongsTo(Teacher::class, 'teacher');
}

Teacher

protected $fillable = [
    'user', 'birth', 'about',
];

public function user()
{
    return $this->hasOne(User::class, 'user');
}

Controller Where I try to raise a teacher:

$f_teacher = $request->only('birth', 'about');
$f_user = $request->except('birth', 'about', '_token');

$teacher = new Teacher($f_teacher);
$teacher->user()->save( new User($f_user) );
$teacher->save();

When running this page, the following error appears:

Queryexception in Connection.php line 770: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user' in 'field list' (SQL:

insert into users (name, email, username, password, user, updated_at, created_at) values (Nome do professor, [email protected], user-prof, senha-criptografada, ,2017-01-07 00:26:44, 2017-01-07 00:26:44))

I know the mistake is because the Laravel is reversing the relation, is interpreting that the table users has the FK user and the table teachers not have, I tried to reverse, putting Hasone on the user model and Belongsto in the teacher’s model, but as expected it didn’t work. Why is this relationship being reversed? How to solve?

  • That code of insert is that right? There are two commas then creating a space where the user. I have seen other examples where the answers ask you to pay attention to the dates. You have a model that creates timestamps, but the database does not have the appropriate field for the dates.

  • 1

    @Nottherealhemingway already checked the timestamps, this is precisely the problem, which I quoted in the last paragraph of the question, in fact the table users nor has the column user, this column belongs to table teachers, but Laravel is reversing the relationship I created. I created something similar to: Teacher hasOne User but he’s interpreting it as User hasOne User

  • Ah, damn it, I’m sorry! I should have read it carefully. Back to the lab

  • 1 user can be a teacher is that it? If it is different the Migration and the models to work.

  • @Virgilionovic basically yes, because I’m going to have two types of users, corporations and teachers, so I unified the access table, with the attributes that they both have in common. So in my view, a teacher has a user, just as a corporation will have a user.

  • A user can be both teacher and corporation?

  • 1

    @Virgilionovic, no, will always be one for one, user would only function as a extends for teacher and corporation, only to reuse fields that the two have in common, not to have to have the attributes email, password.

  • @Ivcs I made a catch I changed some points of Teacher (both Migration and model) and created a record for you to understand.

Show 3 more comments

1 answer

2


Relationship 1:1 Laravel

Following the documentation and comments, the models and migrations need to be changed to fit the relationship 1:1 proposed by .

Relação

inserir a descrição da imagem aqui


Migrations

Usuario (Users)

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Users extends Migration
{   
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name', 150);
            $table->string('username', 20)->unique();
            $table->string('email', 100)->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::drop('users');
    }
}

Teachers (Teacher)

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Teacher extends Migration
{   
    public function up()
    {
        Schema::create('teachers', function (Blueprint $table) {
            $table->integer('userid')
                 ->unsigned();
            $table->primary('userid');
            $table->date('birth');
            $table->string('about');
            $table->foreign('userid')
                 ->references('id')
                 ->on('users');
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::drop('teachers');
    }
}

The great change in migration is in regards Teacher, the key to the relationship cannot be self-improvement, because it receives the key value of the relationship with User and is the primary key table teachers. Summarizing the table/field users.id relates to teachers.userid, thus generating a relationship 1:1.

Models

User

<?php namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    //configurações a serem observadas
    protected $primaryKey = "id";
    protected $table = "users";
    public $incrementing = true;

    protected $fillable = [
        'username', 'email', 'password', 'name', 'remember_token',
    ];

    protected $hidden = ['password', 'remember_token'];
    public function teacher()
    {
        return $this->hasOne(Teacher::class, 'userid','id');
    }
}

Teacher

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Teacher extends Model
{
    //configurações a serem observadas
    protected $primaryKey = "userid";
    protected $table = "teachers";
    public $incrementing = false;

    protected $fillable = ['userid', 'birth', 'about'];

    public function user()
    {
        return $this->belongsTo(User::class, 'userid', 'id');
    }
}

As already said the change is also in the model Teacher, where it is to be indicated:

  • Primary key
  • Disable auto-incrementing of this field which by default is true;

and is on the model in that part:

//configurações a serem observadas
protected $primaryKey = "userid"; //setando a chave primária
protected $table = "teachers"; //nome da tabela na base de dados
public $incrementing = false; //desabilitando auto-incremento

that is, who generates the identification of the relationship of the tables is the model User and who gets this key is the model Teacher. User has a hasOne with Teacher, while Teacher has a belongsTo with User.


Create a record:

//primeiro cria user
$data0['name'] = 'Usuario 1';
$data0['username'] = 'usuario1';
$data0['email'] = '[email protected]';
$data0['password'] = bcrypt('usuario1');
$user = new App\Models\User($data0);
$user->save(); // salva

//depois cria teacher para esse user.
$data1['birth'] = date('Y-m-d');
$data1['about'] = 'Sobre usuario1';
$user->teacher()->create($data1);

//exibindo informações.
var_dump($user->with('teacher')->where('id', $user->id)->first());

Seeking registration:

>>> $c->with('teacher')->find(6);
=> App\Models\User {#731
     id: 6,
     name: "Usuario 1",
     username: "usuario1",
     email: "[email protected]",
     created_at: "2017-01-07 12:23:39",
     updated_at: "2017-01-07 12:23:39",
     teacher: App\Models\Teacher {#738
       userid: 6,
       birth: "2017-01-07",
       about: "Sobre usuario1",
       created_at: "2017-01-07 12:23:39",
       updated_at: "2017-01-07 12:23:39",
     },
   }
>>>

Deleting this record and relation:

>>> $d = $c->find(6); //busca
=> App\Models\User {#711
     id: 6,
     name: "Usuario 1",
     username: "usuario1",
     email: "[email protected]",
     created_at: "2017-01-07 12:23:39",
     updated_at: "2017-01-07 12:23:39",
   }
>>> $d->teacher()->delete(); //excluindo teacher
=> 1
>>> $d->delete(); //excluindo user
=> true
>>>

References:

  • 1

    It worked perfectly, yesterday a little after publishing the question had changed the Migrations, leaving similar, but I missed the relationship of the tables in the model. Thank you very much, I understood the functioning of the same, I did not know the incrementing rs.. Congratulations on a very detailed answer :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.