I have a simple relationship in laravel eroquent
Here is the bidders table creation
public function up()
{
Schema::create('bidders', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('params_name');
$table->string('params_value');
$table->string('bidder_name');
$table->timestamps();
});
}
Here is bidder_parameter table creation
public function up()
{
Schema::create('bidder_parameters', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('bidder_id');
$table->foreign('bidder_id')->references('id')->on('bidders')->onDelete('cascade');
$table->timestamps();
});
}
Here is a bidder model
class Bidder extends Model
{
protected $table = 'bidders';
protected $fillable = [
"params_name",
"params_value",
"bidder_name"
];
public function page()
{
return $this->hasMany('App\Page');
}
public function parameters()
{
return $this->hasMany('App\BidderParameter');
}
}
and here is BidderParameter model
class BidderParameter extends Model
{
public function parameters()
{
return $this->belongsTo('App\Bidder');
}
}
Here is parameter controller for inserting data to database
public function store(Request $request){
// dd($request);
if($request->ajax())
{
$rules = array(
'params_name.*' => 'required',
'params_value.*' => 'required',
'bidders_name.*' => 'required'
);
$error = Validator::make($request->all(), $rules);
if($error->fails())
{
return response()->json([
'error' => $error->errors()->all()
]);
}
$params_name = $request->params_name;
$params_value =$request->params_value;
$bidders_name =$request->bidders_name;
for($count = 0; $count < count($params_name); $count++)
{
$data = array(
'params_name' => $params_name[$count],
'params_value' => $params_value[$count],
'bidders_name' => $bidders_name[$count],
);
$insert_data[] = $data;
// dd($insert_data);
}
Bidders:insert($insert_data);
return response()->json([
'success' => 'Data Added successfully.'
]);
}
}
Now when I submit data to the database 'bidders tablehave data saved into it butbidder_parameter` is empty
What is wrong with my code?
Many to many relationship contains 3 tables. 2 tables are main and 3rd table is combination of those 2 tables' primary keys.
For example
User can have many roles
and
Role can belong to many users
so that requires many to many relationship
So we need a database schema like this:
Users table -> (id, name ,...) e.g. Jonn Doe with id 1
Roles table -> (id, name, ...) e.g. SUPER_ADMIN with 1
role_user table (id, user_id, role_id) role_id is foreign key of roles table and user_id is foreign key of users table
Now in Model classes:
In User Model
public function roles(){
return $this->belongsToMany(Role::class,'role_user','user_id','role_id');
}
Now in Roles class
public function users(){
return $this->belongsToMany(User::class,'role_user','role_id','user_id');
//note keys are in opposite order as in roles() method
}
Now you can call function from User instance and Role instance where you want
$user->roles // as collection
$user->roles() // as eloquent instance
Also
$role->users // as collection
$role->users() // as eloquent instance
You can read more here
Related
I am using laravel factory method for populating my database table. I have three models and their relationship with each other are given below:
**User model**
class User extends Authenticatable
{
public function books() {
return $this->hasMany('App\Book', 'user_id', 'id');
}
public function ratings() {
return $this->hasMany('App\Rating', 'user_id', 'id');
}
}
**Book Model**
class Book extends Model
{
public function user() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
public function ratings() {
return $this->hasMany('App\Rating', 'book_id', 'id');
}
**Rating Model**
class Rating extends Model
{
public function book() {
return $this->belongsTo('App\Book', 'book_id', 'id');
}
public function user() {
return $this->belongsTo('App\User', 'user_id', 'id');
}
}
And my factory definition for model Book and Rating look like this:
$factory->define(Book::class, function (Faker $faker) {
return [
'title' => $faker->title,
'description' => $faker->sentence
];
});
$factory->define(Rating::class, function (Faker $faker) {
return [
'rating' => $faker->numberBetween(1,5)
];
});
Database table look like this:
User table:
id,name,email,password
Book table:
id,user_id,title,description
Rating table:
id,user_id,book_id,rating
The code for calling factory is given below:
public function run()
{
//create 10 users
$user = factory(App\User::class,10)->create();
// create 2 books for each user
$user->each(function ($user) {
$book = $user->books()->saveMany(factory(App\Book::class,2)->make());
});
});
So with this run method i am able to create 10 users and each user have two books. But i also want to have each book rated by 3 different users. So what extra code should i add in above method to achieve this.
I have a simple approaching method that you may consider
//create 10 users
$user = factory(App\User::class,10)->create();
$id_arr = Arr::pluck($user , 'id'); // get user id array
// create 2 books for each user
$user->each(function ($user) use($id_arr) {
$books = $user->books()->saveMany(factory(App\Book::class,2)->make());
$shuffle_id = Arr::shuffle($id_arr); // shuffle user_id each time create user successfully
// add 3 rates for each book with different user
$books->each(function ($book) use($shuffle_id) {
$book_id = $book['id'];
for ($i=0; $i<3; $i++){
$user_id = $shuffle_id[$i]; // get id in first 3 of shuffle_id array (this will make sure, user_id will never be duplicated
factory(App\Rate::class)->create(['book_id'=>$book_id, 'user_id' => $user_id]);
}
});
});
Hope it will help
i wonder to know how to insert data into pivot table when using a belongsto many relationship i can read the data from database now but i dont know how to store data in database and in my invoice_product table here is the code
model of invoce :
class Invoice extends Model
{
protected $fillable = ['title','description','client_id','product_id'];
public function user() {
return $this->hasOne('App\Client','id','client_id');
}
public function products()
{
return $this->belongsToMany('App\Product', 'invoice_product', 'invoice_id')
->withPivot('product_quantity')
->as('invoice_products_pivot');
}
}
controller of invoice :
public function store(Request $request)
{
//Validate
$request->validate([
'title' => 'required|min:3',
'description' => 'required',
]);
$invoices = Invoice::create([
'title' => $request->title,
'description' => $request->description,
'client_id' => $request->client_id,
'product_id' => $request->product_id,
]);
return redirect('admin/invoices/' . $invoices->id);
}
this stores an invoice into invoice table but i want to get the client_id and product_id or ids cause it must be multiple products and save them into invoice_product table which migration is down here
public function up()
{
Schema::create('invoice_product', function (Blueprint $table) {
$table->increments('id');
$table->integer('client_id');
$table->integer('product_id');
$table->integer('product_quantity');
$table->timestamps();
});
}
to insert data into intermediate or pivot table for many to many relationshiop
you can use attach eloquent method like below
$invoice->products()->attach($product_id)
$product->invoices()->attach($invoice_id)
but your invoice product migration looks a bit odd it should be like this
public function up()
{
Schema::create('invoice_product', function (Blueprint $table) {
$table->increments('id');
$table->integer('invoice_id'); // id of the invoice table
$table->integer('product_id'); // id of the product table
$table->integer('product_quantity'); // client_id should go to the invoice table
$table->timestamps();
});
}
User model:
public function userable()
{
return $this->morphTo();
}
Mentor model:
public function user()
{
return $this->morphOne('App\Models\User', 'userable');
}
The student model looks the same as the mentor model.
The tables for Students and Mentors contain a custom PK called user_id which references the primary key on the users table.
So what I'm trying to do is the following:
$user = new User();
$user->first_name = 'Trajce';
$user->last_name = 'Petkoski';
$user->nickname = 'ads';
$user->administrator = '0';
$user->email = 'asd';
$user->password = Hash::make('test');
$user->save();
$mentor = new Mentor();
$mentor->user_id = $user->id;
$mentor->save();
$user->userable_id = $mentor->user_id;
$mentor->user()->save($user);
However, on the Users table, userable_id is being set to 0 while userable_type value is set to the corret value. The issue here is that save() sets it to a predefined 0. Any idea what's going on behind the scenes?
Try this to add data to Polymorphic relation (morphOne):
Migrations:
// User
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('first_name');
$table->string('last_name');
$table->string('nickname');
$table->integer('administrator');
$table->string('email');
// add these two for the relation to work
$table->integer('userable_id')->unsigned();
$table->string('userable_type');
//
$table->rememberToken();
$table->timestamps();
});
// Mentor
Schema::create('mentors', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
User Model
public function userable()
{
return $this->morphTo();
}
Mentor Model
public function user()
{
return $this->morphOne('App\Models\User', 'userable');
}
Association Code:
$mentor = new Mentor();
// this is important: first save mentor
$mentor->save();
$userdata = [
'first_name' => 'Trajce',
'last_name' => 'Petkoski',
'nickname' => 'ads',
'administrator' => 0,
'email' => 'asd',
'password' => Hash::make('test')
];
$mentor->user()->create($userdata);
This works like a charm in my Laravel 5.4 test installation
Try this
public function users() {
return $this->morphMany('App\Models\User', 'userable');
}
I have 3 models: Priority, Task and User
Priority
can be assigned to many tasks
belongs to one user
Code ...
class Priority extends Model
{
protected $fillable = ['name', 'hexcolorcode'];
protected $casts = [
'user_id' => 'int',
];
public function task()
{
return $this->hasMany(Task::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Task
has one priority assigned
belongs to one user
Code ...
class Task extends Model
{
protected $fillable = ['name'];
protected $casts = [
'user_id' => 'int',
];
public function user()
{
return $this->belongsTo(User::class);
}
public function priority()
{
return $this->hasOne(Priority::class);
}
}
User
can have many tasks
can have many priorities
Code ...
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function tasks()
{
return $this->hasMany(Task::class);
}
public function priorities()
{
return $this->hasMany(Priority::class);
}
}
TaskController
class TaskController extends Controller
{
protected $tasks;
private $priorities;
public function __construct(TaskRepository $tasks, PriorityRepository $priorities)
{
$this->middleware('auth');
$this->tasks = $tasks;
$this->priorities = $priorities;
}
public function index(Request $request)
{
return view('tasks.index', [
'tasks' => $this->tasks->forUser($request->user()),
'priorities' => $this->priorities->forUser($request->user())
]);
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'description' => 'required',
'priority' => 'required'
]);
$request->user()->tasks()->create([
'name' => $request->name,
'description' => $request->description,
'priority_id' => $request->priority
]);
return redirect('/tasks');
}
public function edit(Task $task)
{
$this->authorize('edit', $task);
return view('tasks.edit', compact('task'));
}
public function update(Request $request, Task $task)
{
$this->validate($request, [
'name' => 'required|max:255',
]);
$task->update($request->all());
return redirect('/tasks');
}
public function destroy(Request $request, Task $task)
{
$this->authorize('destroy', $task);
$task->delete();
return redirect('/tasks');
}
}
Error
Now when I want to store a task it gives me following error:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails (tasks.tasks,
CONSTRAINT tasks_priority_id_foreign FOREIGN KEY (priority_id)
REFERENCES priorities (id)) (SQL: insert into tasks (name,
user_id, updated_at, created_at) values (test task, 1,
2016-05-01 14:11:21, 2016-05-01 14:11:21))
Is it possible with this construct or do I have to use Polymorphic Relations between priority table and tasks table?
My Tables
Database Model Picture: http://picpaste.de/mysql-kBH4tO5T.PNG
class CreatePrioritiesTable extends Migration
{
public function up()
{
Schema::create('priorities', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->char('name');
$table->char('hexcolorcode', 7);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
});
}
}
class CreateTasksTable extends Migration
{
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('name');
$table->text('description');
$table->integer('priority_id')->unsigned();
$table->timestamps();
$table->foreign('priority_id')->references('id')->on('priorities');
$table->foreign('user_id')->references('id')->on('users');
});
}
}
UPDATE
PriorityController
class PriorityController extends Controller
{
protected $priorities;
public function __construct(PriorityRepository $priorities)
{
$this->middleware('auth');
$this->priorities = $priorities;
}
public function index(Request $request)
{
return view('priority.index', [
'priorities' => $this->priorities->forUser($request->user()),
]);
}
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required|max:255',
'hexcolorcode' => 'required|max:7'
]);
$request->user()->priorities()->create($request->all());
return redirect('/priorities');
}
public function edit(Priority $priority)
{
$this->authorize('edit', $priority);
return view('priority.edit', compact('priority'));
}
public function update(Request $request, Priority $priority)
{
$this->validate($request, [
'name' => 'required|max:255',
'hexcolorcode' => 'required|max:7'
]);
$priority->update($request->all());
return redirect('/priorities');
}
public function destroy(Request $request, Priority $priority)
{
$this->authorize('destroy', $priority);
$priority->delete();
return redirect('/priorities');
}
}
In your store method. The create method it says :
user->tasks(). This bit will only inserting data in user and tasks table. Thats why you have foreign key error. As you are not updating one of your tables(priority) and also you have added foreign keys in tables as i csn see from migration.
What you are trying to achieve is right if you had a pivot table called task_user where you had userid, taskid and a priority_id. That would be perfect as you would simply update the priority column with userid and taskid. Thats one way but it will require few changes OR you can insert data into user and tasks table seperately for which you will need to just change the query. What do you prefer? I can show you an example for which you like.
//for Priority
// store
$priorities = new Priority;
$priorities->name = Input::get('priority_name');
$priorities->hexcolorcode = Input::get('hexcolorcode');
$priorities->save();
$priority = Priority::select('id')->orderBy('created_at', 'desc')->first();
//for Task
$tasks = new Task;
$tasks->name = Input::get('task_name');
$tasks->priority_id = Input::get('priority');
$priorities->save();
// redirect
return Redirect::to('some view please change this');
Please explain views or show screenshots, how are you handling it. For now, I have given you the solution with one controller handling priorities and tasks.
SOLUTION
I added the priority_id attribute to the fillable array inside the task model.
protected $fillable = ['name', 'description', 'priority_id'];
I had an understanding problem, because user_id is assigned automatically from the framework, but it isn't specified in fillable array. That's because I say $request->user->tasks->create(); it is assigned from the framework, but priority_id is assigned through the user, so it is mass assigned and need to be specified in the fillable array.
#Murlidhar Fichadia
Looking for a simple way of doing the following in Laravel 5.
Imagine these models and interface
Competition
User
Team
Participant (Interface which User and Team implements)
A competition will have a many-to-many relationship to is participants, which can be either users or teams. So I need the competition_participant pivot table to have the following columns to define the models
competition_id
participant_id
participant_type
But how do I write a relation on the Competition model, so it knows which model it should fetch from the database, and at the same time return a collection of mixed models or of the Interface type?
You had some confusions about which tables should get which columns.
Your participants table needs to be a table for managing the polymorphic relations of users and teams. It receives a particpatable_id and particpatable_type as well as an id and timestamps() at the very minimum.
Then you need an additional table called competition_participant which will manage the belongs to many between competitions and your polymorphic table participants.
This will allow you to relate your participants to your competitions. This way, you can grab all participants by a competition, call the $participant->participatable attribute on it which would return either an App\User or an App\Team depending on what type the participant is.
This is all tested.
Migrations
public function up()
{
Schema::create('competitions', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('teams', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('participants', function(Blueprint $table) {
$table->increments('id');
$table->integer('participatable_id');
$table->string('participatable_type');
$table->timestamps();
});
Schema::create('competition_participant', function(Blueprint $table) {
$table->integer('competition_id');
$table->integer('participant_id');
});
}
Models
class Competition extends Model
{
public function participants()
{
return $this->belongsToMany(Participant::class);
}
}
class Participant extends Model
{
public function participatable()
{
return $this->morphTo();
}
public function competitions()
{
return $this->belongsToMany(Competition::class);
}
}
class Team extends Model
{
public function participants()
{
return $this->morphMany(Participant::class, 'participatable');
}
}
class User extends Authenticatable
{
public function participants()
{
return $this->morphMany(Participant::class, 'participatable');
}
}
Seeds
public function run()
{
$faker = Faker\Factory::create();
// Seed Users Table
DB::table('users')->delete();
$users = [];
for($i = 0; $i < 100; $i++) {
$users[] = [
'name' => $faker->name,
'email' => $faker->email,
'password' => Hash::make($faker->password),
'created_at' => new DateTime,
'updated_at' => new DateTime
];
}
DB::table('users')->insert($users);
// Seed Teams Table
DB::table('teams')->delete();
$teams = [];
for($i = 0; $i < 20; $i++) {
$teams[] = [
'name' => 'Team ' . ucwords($faker->domainWord),
'created_at' => new DateTime,
'updated_at' => new DateTime
];
}
DB::table('teams')->insert($teams);
// Seed Participants Table
DB::table('participants')->delete();
// Insert some of our users as participants
$users = App\User::limit(20)->orderByRaw('rand()')->get();
foreach($users as $user) {
$user->participants()->create([]);
}
// Insert some of the teams as participants
$teams = App\Team::limit(10)->orderByRaw('rand()')->get();
foreach($teams as $team) {
$team->participants()->create([]);
}
// Seed Competitions Table
DB::table('competitions')->delete();
$competitions = [];
for($i = 0; $i < 10; $i++) {
$competitions[] = [
'name' => $faker->company,
'created_at' => new DateTime,
'updated_at' => new DateTime,
];
}
DB::table('competitions')->insert($competitions);
// Seed Competitions Participants Relationships
DB::table('competition_participant')->delete();
// Sign up each participant to 3 random competitions
$participants = App\Participant::all();
$competitions = App\Competition::all();
foreach($participants as $participant) {
$participant->competitions()->sync($competitions->shuffle()->take(3));
}
}
Usage
$competition = App\Competition::with('participants')->has('participants')->first();
foreach($competition->participants as $participant) {
echo get_class($participant->participatable); // Will output either App\User or App\Team
echo "<br />";
}
This is just a copy paste from the Laravel documentation about many to many polymorphic relationships.
To help you understand better this is the mapping between your models and the models that are on the Laravel documentation:
users == posts
teams == videos
competitions == tags
competitionables == tags
This how you should implement your polymorphic relationship, remember whenever you feel confused just look at the documentation and the mapping between your models and the documention models:
Tables:
users
id - integer
name - string
teams
id - integer
name - string
competitions
id - integer
name - string
competitionables
competition_id - integer
competitionable_id - integer
competitionable_type - string
Model Structure
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get all of the Competition for the user.
*/
public function competitions()
{
return $this->morphToMany('App\Competition', 'competitionable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
/**
* Get all of the Competition for the Team.
*/
public function competitions()
{
return $this->morphToMany('App\Competition', 'competitionable');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Competition extends Model
{
/**
* Get all of the users that are assigned to this Competition.
*/
public function users()
{
return $this->morphedByMany('App\User', 'competitionable');
}
/**
* Get all of the Teams that are assigned to this Competition.
*/
public function teams()
{
return $this->morphedByMany('App\Video', 'competitionable');
}
}
Retrieving The Relationship
$user = App\User::find(1);
foreach ($user->competitions as $competition) {
//
}
or the other way
$competition = App\Competition::find(1);
foreach ($competition->users as $user) {
// do something with your users
}
foreach ($competition->teams as $team) {
// do something with your teams
}