Laravel eloquent inserting data only in Pivot table - php

Backround information
Using Laravel I'm building an application where I want to link a Company profile to a Station.
Company.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
protected $guarded = [];
protected $table = 'companies';
public function user()
{
return $this->hasMany('App\User');
}
public function station()
{
return $this->belongsToMany('App\Station')->withPivot('company_stations');
}
public function line()
{
return $this->belongsToMany('App\Line');
}
}
Station.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Station extends Model
{
protected $guarded = [];
protected $table = 'stations';
public function lines()
{
return $this->belongsToMany('App\Line');
}
public function company()
{
return $this->belongsToMany('App\Company')->withPivot('company_stations');
}
}
company_stations migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCompanyStationsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('company_stations', function (Blueprint $table) {
$table->id();
$table->integer('company_id')->unsigned();
$table->integer('station_id')->unsigned();
$table->boolean('following')->default(false);
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('company_stations');
}
}
I also have a migration company_stations, but no Model for it.
The question
I want to create a checkbox on the station view where the currently logged in Company ID is linked to the Station ID in the pivot table to keep track of which stations the company is following and wether the company has completed that station or not.
What would be the easiest and most clean approach to this? Do I make a new Model CompanyStation + controller or can this be filled in from the Company or Station controller?

You can use sync method of belongsTomany relationship.
$station = Station::find($stationid);
$station->company()->sync([1,2,3]); //1,2,3 is the company ids which you're selection through checkbox.
//this will drop all the existing companies except the companies with id 1,2,3. If these ids don't exist it will attach them (still dropping the existing ones).

if you add a column to your piviot table company_stations example: 'completed' you can access it with
foreach ($company->stations as $station) {
dd($station->pivot->completed);
}
you can add that data via
$company->stations()->attach($station->id, ['completed' => true]);
Query it
//only show me completed company stations. (from piviot)
Company::whereHas('stations', function($q) {
$q->where('company_stations.completed', true);
})
->get();

Related

Issues with pivot table with Laravel

I have a problem with creating pivot table in Laravel. That's the first time I'm using it, and after searching on Internet, I can't manage to fix my issue.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'champions_teams.teams_id' in 'field list' (SQL: select `champions`.*, `champions_teams`.`teams_id` as `pivot_teams_id`, `champions_teams`.`champions_id` as `pivot_champions_id`, `champions_teams`.`champion_id` as `pivot_champion_id` from `champions` inner join `champions_teams` on `champions`.`id` = `champions_teams`.`champions_id` where `champions_teams`.`teams_id` = 1) (View: C:\laragon\www\proyecto-web\resources\views\teams\teamIndex.blade.php)
Following, the way I created my classes "Champions" and "Teams", with my pivot table migration.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\softDeletes;
class Teams extends Model
{
use SoftDeletes;
protected $table = 'teams';
protected $fillable = ['user_id','name','rank','region'];
public function user(){
return $this->belongsTo(User::class);
}
public function champions(){
return $this->belongsToMany(Champions::class)->withPivot('champion_id');
}
public function files(){
return $this->morphMany(File::class, 'model');
}
public function setNameAttribute($value){
$this->attributes['name'] = strtoupper($value);
}
public function getTeamsNameAttribute(){
return $this->name;
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Champions extends Model
{
protected $table = 'champions';
protected $fillable = ['name','health_points','type','role'];
public function teams(){
return $this->belongsToMany(Teams::class)->withPivot('team_id');;
}
public function items(){
return $this->hasMany(Items::class, 'champion_id');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class PivotTables extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('champions_teams', function(Blueprint $table){
$table->unsignedBigInteger('champion_id');
$table->unsignedBigInteger('team_id');
$table->foreign('champion_id')
->references('id')
->on('champions')
->onDelete('cascade');
$table->foreign('team_id')
->references('id')
->on('teams')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
//
}
}
Thanks for your help ! You can also access the whole code right here : https://github.com/ValentinDelpy/proyecto-web
Many to Many
Since you are not following the name conventions which Laravel expects, you should customize the name of the joining table, the column names of the keys on the table by passing additional arguments to the belongsToMany method. The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to:
class Champions extends Model
{
public function teams(){
return $this->belongsToMany(Teams::class, 'champions_teams', 'team_id', 'champion_id');
}
}
class Teams extends Model
{
public function champions(){
return $this->belongsToMany(Champions::class, 'champions_teams', 'champion_id', 'team_id');
}
}
Seems You have collision with teams and team.
You model is named Teams (should be Team).
Checkout how to make many to many relations propely:
Laravel docs
Probably Laravel is generating the id from the Model name, so if the Project is brand new, just change it, otherwise, you have to declare the foreign keys name in the belogsToMany function (check https://laravel.com/api/6.x/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_belongsToMany).
Also keep in mind that the witPivot function is to let Laravel know the existence of other fields more than the only 2 foreign keys, not the foreign keys themself (check https://laravel.com/api/6.x/Illuminate/Database/Eloquent/Relations/BelongsToMany.html#method_withPivot)

Laravel relationship design

I'm working on team management project.
I have a problem with doing relationships.
I want to display users in boards, but also want to look good and easy to read. I already designed relationships but when I saw JSON output of relationships, it was completely messed.
Is there some way how to display relationship data this way?
{
"id": 1,
"name: "Test",
"members": [
{
... user model here
"name": "Peter",
"email": "peter#peter.com",
}
]
}
My migrations:
Boards migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateBoardsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('boards', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('boards');
}
}
Membership migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMembershipsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('memberships', function (Blueprint $table) {
$table->increments('id');
$table->integer('board_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('memberships');
}
}
EDIT:
Models
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Board extends Model
{
protected $fillable = ['name'];
public function members() {
return $this->hasMany(Membership::class)->with('user');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Membership extends Model
{
protected $fillable = ['board_id', 'user_id'];
protected $hidden = ['created_at', 'updated_at'];
public function user() {
return $this->hasOne(User::class, 'id', 'user_id');
}
}
You can try to define the relationships in the models as a Many to Many one, i.e.:
class User
{
public function boards()
{
return $this->belongsToMany('App\Board', 'memberships', 'user_id', 'board_id');
}
}
class Board
{
public function members()
{
return $this->belongsToMany('App\User', 'memberships', 'board_id', 'user_id');
}
}
With that relations defined you don't really need a Membership Model if it has not additional fields, and you can write code like that:
User::find($id)->boards
Board::find($id)->members
Board::with('members')->find($id)
You could read also the documentation on Many to Many Relationships

Laravel - How to find foreign key value

first time working with Laravel and PHP. I am trying to insert row in the table profile where the attribute uID is a foreign key referencing to uID on user table, but getting errors. How do I insert just the summary attribute of the profile and set the uID (foreign key) automatically. I can insert users with uID without any problems. Here are my model and controller files. Thanks!
user model
namespace App;
use Illuminate\Database\Eloquent\Model;
class user extends Model
{
// specify which attributes can be filled out during registration
public $timestamps = false;
protected $fillable=['firstname','lastname','email','password',];
public function profile(){
return $this->hasOne(profile::class);
}
}
profile model
namespace App;
use Illuminate\Database\Eloquent\Model;
class profile extends Model
{
//
public $timestamps = false;
protected $fillable = ['summary',];
public function user(){
return $this->belongsTo(user::class);
}
}
profile migration
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProfilesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
// create profile table
Schema::create('profiles', function (Blueprint $table) {
$table->increments('pID');
$table->timestamp('created_at')->useCurrent();
$table->string('summary')->default('');
$table->unsignedInteger('uID');
$table->foreign('uID')->references('uID')->on('users')->onDelete('cascade');
});
}
}
profile controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\profile;
class ProfileController extends Controller
{
public function create()
{
//
return view('profile.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
// used to store user profile after validation
$this->validate($request,[
'summary' => 'required'
]);
$profile = new profile([
'summary' => $request->get('summary'),
'uID' => $request->user()->uID
]);
return redirect()->route('profile.create')->with('success','Profile created');
}
}
Welcome to Laravel :)
On your profile Model on the user method you need to define the foreign key.
public function user(){
return $this->belongsTo(user::class, 'uID');
}
If you don't provide the foreign key, it will look for user_id field.
Alright, a couple of things that could need to be sort out:
Declare your Classes with a capitalised letter. It is Profile not profile. Avoid plurals as well. More on that can be explored reading about PSR-x;
You have deviated from the laravel way in regards to foreign keys. Therefore, you need to specify in your relationship which are the keys to connect with:
Also, notice how I changed your method name from user -> users
public function users()
{
return $this->belongsTo(user::class, 'id', 'uID');
}
As well as for your profile relationship:
public function profiles(){
return $this->hasOne(profile::class, 'uID', 'id');
}
hi put your database here and add forign key to the model

Can I use where in eloquent while giving it an object?

I'm new to Laravel & Eloquent, I'm coming from Django.
In Django I can create a filter on my results and use an object to filter the results...
I'm trying to figure out if I could do this in Laravel/Eloquent also...
Here's what I'm trying to do....
create_messages_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateMessagesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('messages', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('user_id');
$table->string('message');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('messages');
}
}
Message.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
MessageController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Message;
use Illuminate\Support\Facades\Auth;
class MessageController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$messages = Message::where("user", Auth::user())->get();
dd($messages);
return $messages;
}
}
The problem is that when the controller index() function is routed too... I get an error saying "user" column does not exist... and it doesn't but I assumed the models user() function would take care of that and that I would be able to compare it's returning object with Auth::user().
Am I wrong, or am I just doing it wrong?
In the "where" query, the first parameter must be a column in the database. If you want to make use of a "user" column, I'll suggest you add a user column to your table.
I think the auth:user() is to authenticate the current user.
So laravel eloquent is only alerting you that the "user" column does not exist. I will suggest you create a user column, and see what happens next.

Undefined table: 7 ERROR: relation "expenses" does not exist

Since i am a spanish speaker, i wrote the controllers and models of income and expense in spanish; while all the rest were on english..
I renamed and changed manually Routes, Controllers, Migrations and even Models.
And when i run php artisan migrate:reset this is my error.
Undefined table: 7 ERROR: relation "expenses" does not exist (SQL: alter table "expenses" drop column "location_id")**
I use psgql and laravel 5.3
This is my code:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Expense extends Model
{
protected $fillable = ['id', 'description', 'quantity'];
public function locations()
{
return $this->hasMany('App\Location');
}
public function icons()
{
return $this->hasMany('App\Icon');
}
public function types()
{
return $this->hasMany('App\Type');
}
public function stores()
{
return $this->hasMany('App\Store');
}
}
Migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateExpensesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('expenses', function (Blueprint $table) {
$table->increments('id');
$table->float('quantity');
$table->string('description');
$table->integer('location_id')->unsigned();
$table->integer('icon_id')->unsigned();
$table->integer('type_id')->unsigned();
$table->integer('store_id')->unsigned();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('expenses');
}
}
Location Migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateLocationsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('locations', function (Blueprint $table) {
$table->increments('id');
$table->string('address');
$table->float('lat');
$table->float('long');
$table->integer('store_id')->unsigned();
$table->timestamps();
$table->foreign('store_id')->references('id')->on('stores')->onDelete('cascade');
});
Schema::table('expenses', function (Blueprint $table) {
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('expenses', function (Blueprint $table) {
$table->dropColumn('location_id');
});
Schema::dropIfExists('locations');
}
}
Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $fillable = ['id', 'address', 'lat', 'long'];
public function expenses()
{
return $this->belongsTo('App\Expense');
}
public function stores()
{
return $this->hasOne('App\Store');
}
}
Hope you can help me.
When it says
relation "expenses" does not exist
It usually happens when your expenses table must have been dropped before migration:reset rolled back CreateLocationsTable.
Check the order of execution of your migrations.
As you were trying to reset, to fix it now, open your database, drop all tables manually and execute migrate again.
Schema::table('expenses', function (Blueprint $table) {
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
});
change this to
Schema::alter('expenses', function (Blueprint $table) {
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
});
I had this error. I had to resolve it by adding the prefix of the database to my model. There is a way to change this in the database, and it is supposed to be changed. it's something, like $user, public. It's the schema profile. Mine is changed when I login, but for some reason the model is not binding to schema. So I had to specify it in the model. Instead of
protected $table = 'table_name';
I had to do
protected $table = 'schema_name.table_name';
Note: By schema_name or table_name, I'm not referring for you to put schema_ then the name. That is just so it's easier to read.
The model is located in the model folder under the App/Models folder depending on which version of Laravel you using and how your Models are organized. If your model name is not the same as the table name, then you will need to put the protected $table. But if the schema is not there, then you will need to add that.
I do have this set in my DB_DATABASE_SECOND= in .env file. But it somehow still doesn't pick up the prefix.
But yeah. Pretty much I couldn't find the answer anywhere, but I
Solution found in:
Laravel assumes the database table is the plural form of the model name
https://laravel.com/docs/8.x/eloquent#table-names
you need to declare the singularity name of your table.
add this line
protected $table = 'expense'
at the end of your model file
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Expense extends Model
{
protected $fillable = ['id', 'description', 'quantity'];
public function locations()
{
return $this->hasMany('App\Location');
}
public function icons()
{
return $this->hasMany('App\Icon');
}
public function types()
{
return $this->hasMany('App\Type');
}
public function stores()
{
return $this->hasMany('App\Store');
}
protected $table = 'expense';
}

Categories