I have the following with many to many relationship and pivot table. So I would like to update the user_id to 1 pivot table where trophy_id = 3 . However it keeps returning 0 or false.
Trophy.php
public function users()
{
return $this->belongsToMany('App\User', 'trophies_users', 'trophy_id', 'user_id');
}
User.php
public function trophies()
{
return $this->belongsToMany('App\Trophy', 'trophies_users', 'user_id', 'trophy_id');
}
Pivot Table
public function up()
{
Schema::create('trophies_users', function (Blueprint $table) {
$table->id();
$table->integer('trophy_id');
$table->integer('user_id');
$table->timestamps();
});
}
In My controller , I am trying to update the pivot's table
UserController#index
public function index(Request $request)
{
$user = User::find(1);
$trophyId = 3;
$attributes = ['user_id' => 1];
$res = $user->trophies()->updateExistingPivot($trophyId , $attributes);
dd($res); //Keeps returning 0 or false
}
You are passing attribute to updateExistingPivot which is for updating extra attribute on a pivot table.
For example, assume we want to store a color for each companion of user and trophy, we can achieve that by adding an extra column in pivot table and saving color data on it as below:
|---------------------|
| column |
|---------------------|
| id |
|---------------------|
| user_id |
|---------------------|
| trophy_id |
|---------------------|
| color |
|---------------------|
If you want to update a relationship on pivot table, use sync method.
$user=User::find(1);
$trophies_id=[1, 2, 3];
$user->trophies()->sync($trophies_id);
Related
Here's the problem: I can't access items property in user object and they are connected in an Eloquent relationship (one user can have multiple items), but I named the foreignId column as customer_id as opposed to user_id default as referenced table is users. When I tried to access items property in blade, here is error that showed up on display:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'items.user_id' in 'where clause'
select * from items where items.user_id = 3 and items.user_id is not null
So, it clearly searches for the default foreignId column and not for the one I defined as foreignId for that relationship.
Here's relevant part of my code:
Item.php:
public function customer(){
return $this->belongsTo(User::class,'customer_id');
}
User.php:
public function items(){
return $this->hasMany(Item::class);
}
public function get_user($user_name){
return User::where("user_name",$user_name)->first();
}
Migration for items table:
public function up()
{
Schema::create('items', function (Blueprint $table) {
$table->id();
$table->foreignId('wine_id')->constrained();
$table->foreignId('customer_id')->constrained('users');
$table->integer('quantity');
$table->timestamps();
});
}
UserController.php
...
$user = $user_model->get_user($request->user_name);
$request->session()->put("user",$user);
...
Blade:
<?php
$items = session('user')->items;
$empty_cart = true;
foreach($items as $item){
if($wine->id==$item->customer_id){
$empty_cart = false;
return;
}
}
var_dump($empty_cart);
?>
The error is actually in your hasMany relationship, since user_id does not exist in the items migration.
You need to define the foreign key here (as you did in the Item model) since it appears most likely to be customer_id instead.
The error triggers from your blade code here: session('user')->items; -- as soon as items is accessed.
i have three table:
Suppliers
id | name | type
1 | Test1 | Seller
2 | Test2 | Manufacturer
Products
id | name
1 | product1
2 | product2
Prices
id | supplier_id | product_id | price
1 | 1 | 1 | 1000
2| 2 | 1 | 2000
each supplier have many products and each products belong to many suppliers.
Now each supplier can have a separate price for each product.
i have a question that how to create model and table for this scenario?
You will have two tables with models:
Product and Supplier
Within /Database/Migrations create_products table:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
create_suppliers table:
Schema::create('suppliers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('type');
$table->timestamps();
});
You will need a pivot table, so create it with Artisan command:
php artisan make:migration create_product_supplier_table
A quick note: Pivot names should be in alphabetical order to fit laravel name convention. 'P' letter comes first and then 'S' (product_supplier) in this case.
product_supplier table:
Schema::create('product_supplier', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('product_id');
$table->unsignedBigInteger('supplier_id');
$table->integer('price');
$table->timestamps();
});
Now, you will need the following relation declarations in two models
Within App\Product class:
protected $guarded = [];
public function suppliers()
{
return $this->belongsToMany(Supplier::class)->withPivot('price');
}
And also in App\Supplier class:
protected $guarded = [];
public function products()
{
return $this->belongsToMany(Product::class)->withPivot('price');
}
You set it up now. Let's give it a try:
$supplier = App\Supplier::create(['name' => 'supplier1', 'type' => 'seller']);
$product = App\Product::create(['name' => 'product1']);
$supplier->products()->attach($product, ['price' => 80]);
Call it back:
$supplier->products; // it will give you the products that attached to supplier.
So, the any supplier can have any product with any price tag.
I have a users table and a permissions table. One user can have many permissions, and one permission can have many users:
USER ID | PERMISSION ID
1 | 1
1 | 2
2 | 1
2 | 1
There is a linking table called permission_user as defined by the Laravel spec for auto-inferring these tables.
If I define the following functions:
User Model:
public function Permissions()
{
return $this->belongsToMany('App\Permission');
}
Permission Model:
public function Users()
{
return $this->belongsToMany('App\User');
}
I get an error when calling App\User::first()->Permissions()->attach(App\Permission::first()); that says
Illuminate\Database\QueryException : SQLSTATE[42S22]: Column not found: 1054 Unknown column '' in 'field list' (SQL: insert into `permission_user` (``, `user_id`) values (3, 1))
The database migration file:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Carbon\Carbon;
use App\User;
use App\Permission;
use App\Http\Resources\User as UserResource;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('permissions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->timestamps();
});
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('username')->unique();
$table->string('name')->unique();
$table->string('email')->unique();
$table->boolean('verified');
$table->timestamps();
});
Schema::create('permission_user', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('permission_id');
$table->unsignedBigInteger('user_id');
$table->timestamps();
$table->foreign('permission_id')->references('id')->on('permissions');
$table->foreign('user_id')->references('id')->on('users');
});
$this->add_permission('View Projects');
$this->add_permission('Edit Projects');
$this->add_permission('View Users');
$this->add_permission('Edit Users');
$user = new User();
$user->name = 'John Smith';
$user->email = 'john#smith.com';
$user->username = 'jsmith';
$user->verified = 1;
$user->save();
$user->permissions()->attach(Permission::where('name','View Users')->first()->id); // -> This line it can't tell that permission_user.permission_id is where the permission.id field goes;
$perms = $user->permissions()->get();
foreach($perms as $perm)
{
echo $perm->name . '\n';
}
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
Schema::dropIfExists('permission_user');
Schema::dropIfExists('project_user');
Schema::dropIfExists('permissions');
Schema::dropIfExists('deployment_log');
Schema::dropIfExists('branches');
Schema::dropIfExists('projects');
Schema::dropIfExists('users');
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
private function add_permission($permission_name)
{
DB::table('permissions')->insert(
array(
'name' => $permission_name,
)
);
}
}
It appears Laravel(5.8) is unable to disscern from the linking table that permission_id is the field for the foreign reference to the permission.id field even though the database migration reflects that user_id is a foreign reference to user.id and permission_id is a foreign reference to permission.id.
I can solve this by specifying the linking table name, field name, and foreign key name in the belongsToMany function, however, Laravel's own documentation states that this isn't needed when tables and fields are named appropriately, which mine are. Is this a bug in Laravel? Do I need to change the name of the permission_user.permission_id field? How do I solve this without having to specify these names in my models as it's time consuming and not needed according to Laravel(5.8)'s documentation.
According to laravel docs:
[...] Many users may have the role of "Admin". To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns.
The linking table must contain only the foreign keys from each model. Otherwise, you need to specify which relationship table you are using and the primary key for each model of the relation, as specified on laravel documentation.
As i said in the comments section, if you create your permission_user table with only permission_id and user_id columns and with this columns as primary keys, it will work as expected:
Schema::create('permission_user', function (Blueprint $table) {
$table->unsignedBigInteger('permission_id');
$table->unsignedBigInteger('user_id');
$table->foreign('permission_id')->references('id')->on('permissions');
$table->foreign('user_id')->references('id')->on('users');
$table->primary(['permission_id', 'user_id']);
});
Here is a package that i have developed to handle user permissions and you can check the user_has_permissions table definition, which is, basically, a table that does exactly what your permission_user table does, by clicking this link.
Hope it helps.
I have two models
Stations
Operators
I am currently trying to "save" several Operators to a Station
but i want also to be able to "save" the same Operator to another Station.
Example:
+---------------------------------+
| Station | Operator(s) |
|---------------------------------|
| Munich | Lufthansa |
| | KLM |
| | Air Malta |
|---------------------------------|
| Berlin | Lufthansa |
| | KLM |
|---------------------------------|
|------- etc ---------------|
|---------------------------------|
My Stations Table:
Schema::create('stations', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100);
$table->timestamps();
});
My Stations Model:
public function operators() {
return $this->hasMany(Operators::class);
}
My Operators Table:
Schema::create('operators', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100)->unique();
$table->string('email', 100);
$table->boolean('notify')->default(false);
$table->timestamps();
});
My Operators Model:
public function stations() {
return $this->belongsTo(Stations::class);
}
Here i must say that i am creating the Station and trying to add the Operators:
In StationsController:
After receiving the Ids of the Operators and the Name of the Station:
$station = new Stations;
$station->name = request('name');
$station->save();
foreach (request('operators') as $operator) {
$tempOperator = Operators::find($operator);
$station->operators()->associate($tempOperator)->save();
}
The response is:
"Call to undefined method Illuminate\Database\Query\Builder::associate()"
I know there is something wrong with the relations but i cannot figure it out... Thank you in advance
Rollback your migration php artisan migrate:rollback
change your operators table migration like this,
Schema::create('operators', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 100)->unique();
$table->string('email', 100);
$table->boolean('notify')->default(false);
$table->timestamps();
});
you have to create a mapping table like,
Schema::create('station_operators', function (Blueprint $table) {
$table->increments('id');
$table->integer('stations_id')->unsigned();
$table->integer('operators_id')->unsigned();
$table->timestamps();
$table->foreign('stations_id')->references('id')->on('stations');
$table->foreign('operators_id')->references('id')->on('operators');
});
Run migrate php artisan migrate
Your Stations Model:
public function StationOperators() {
return $this->hasMany(StationOperators::class);
}
Your Operators Model:
public function StationOperators() {
return $this->hasMany(StationOperators::class);
}
Your StationOperators Model:
public function Stations() {
return $this->belongsTo(Stations::class);
}
public function Operators() {
return $this->belongsTo(Operators::class);
}
For associate,
$station = new Stations;
$station->name = request('name');
$station->save();
foreach (request('operators') as $operator) {
// $tempOperator = Operators::find($operator);
// $station->StationOperators()->associate($tempOperator)->save();
$data = [
'stations_id' => $station->id,
'operators_id' => $operator,
];
$stationOperator = new \App\StationOperators();
$stationOperator->save();
}
You need an intermediate StationsOperators table.
Then try updating your operators model like this:
public function stations() {
return $this->belongsToMany(Stations::class)->using(StationsOperators::class);
}
Remember:
All custom models used to represent intermediate tables of relationships must extend the Illuminate\Database\Eloquent\Relations\Pivot class.
This is a Many-Many relation. You have to use pivot table.
#ref: https://laravel.com/docs/5.5/eloquent-relationships#many-to-many
The associate method only available for belongsTo relationship, so it won't work for many to many relationship.
You can use the attach method for many to many, here is the example from laravel doc https://laravel.com/docs/5.5/eloquent-relationships#updating-many-to-many-relationships
I have 2 tables A and B.
I make a many to many Relationship with a pivot table called A_B
Now I need to make other ManyToMany Relationship between A_B and User ( U )
So I have another table A_B_U
Now, What I need and can't do it, is writing a relationship from A to A_B_U.
I set U to a vale, so A_B -> A_B_U is now a belongsTo Relationship, I should be able to access it easily, but I can't write it, I can write the first relationship, but then, I can't write the second one.
I don't know neither how to pass a param in ManyToMany Rel.
In fact, it shoud be a belongsTo, not ManyToMany so I'm a bit lost in all that....
Any Idea how to do it?
What it looks like
category_tournament_user
/ \
category_tournament users
/ \
tournaments categories
Migrations
Schema::create('tournaments', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('categories', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('category_tournament', function(Blueprint $table) {
$table->increments('id');
$table->integer('category_id');
$table->integer('tournament_id');
$table->timestamps();
});
Schema::create('category_tournament_user', function(Blueprint $table) {
$table->integer('category_tournament_id');
$table->integer('user_id');
});
Models
class Tournament extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
public function categoryTournaments()
{
return $this->hasMany(CategoryTournament::class);
}
}
class Category extends Model
{
public function tournaments()
{
return $this->belongsToMany(Tournament::class);
}
public function categoryTournament()
{
return $this->hasMany(CategoryTournament::class);
}
}
class CategoryTournament extends Model
{
protected $table = 'category_tournament';
public function category()
{
return $this->belongsTo(Category::class);
}
public function tournament()
{
return $this->belongsTo(Tournament::class);
}
public function users()
{
return $this->belongsToMany(User::class, 'category_tournament_user');
}
}
class User extends Authenticatable
{
public function categoryTournaments()
{
return $this->belongsToMany(CategoryTournament::class, 'category_tournament_user');
}
}
Get all users of a tournament
$tournament = App\Tournament::with('categoryTournaments.users')->find(1);
foreach($tournament->categoryTournaments as $categoryTournament) {
// To get the category of the tournament, this will return an App\Category
$category = $categoryTournament->category;
// If you have a name column on your categories table...
$categoryName = $category->name;
// To get the tournament.
$tournament = $categoryTournament->tournament;
// To get the name of the tourament (if there is a name column)
$tournamentName = $tournament->name;
$tournament->created_at; // etc...
// To get all the people participating in this tournament category
foreach($categoryTournament->users as $user) {
echo $user->email;
}
}
If you need to figure out how to traverse the relationships (getting all tournaments and categories a user is participating in, etc...) please feel free to ask.
Starting at the User
// This will list all tournament and category names a user belongs to.
$user = App\User::with('categoryTournaments.tournament', 'categoryTournaments.category')->find($userId);
foreach($user->categoryTournaments as $categoryTournament) {
echo 'Category Name: '.$categoryTournament->category->name;
echo 'Tournament Name: '.$categoryTournament->tournament->name;
echo '<br>';
}
Edit
users and category_tournament make a belongsToMany relationship.
categories and tournaments make a belongsToMany relationship.
category_tournament also has a belongsTo to both tournaments and categories
There is a possibility we can further simplify this if you remove the tables tournaments and categories and drop all their columns right into category_tournament. That way, you end up with only one belongsToMany relationship to manage.