I'm relatively new in Laravel and I would like to learn how to create recursive relation with 2 foreign keys referencing the primary key.
I have table item_associations which has 2 FK referenced to the item table's PK:
Schema::create('item_associations', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->unsignedInteger('item_id');
$table->foreign('item_id')
->references('id')
->on('items');
$table->unsignedInteger('item2_id');
$table->foreign('item2_id')
->references('id')
->on('items');
});
Here is my ItemAssociation model:
protected $table = 'item_associations';
public function items(){
return $this->belongsTo('App\Models\Item','item_id');
}
public function item2_id(){
return $this->belongsTo('App\Models\Item','item2_id', 'item_id');
}
here is my Item model:
protected $table = 'items';
public function item_associations(){
return $this->hasMany(UserType::class);
}
here is my Welcome controller:
$item_association = DB::table('item_associations')
->join ('items', 'item_associations.item_id', '=', 'items.id')
->join ('items', 'item_associations.item2_id', '=', 'items.id')
->get();
return view('welcome', [
'item_association' => $item_association,
]);
Apparently, I receive an error:
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'items' (SQL: select * from item_associations inner join items on item_associations.item_id = items.id inner join items on item_associations.item2_id = items.id)
in blade I would like to get something like this:
What if you want to add another thing besides gravies?
I can suggest you 2 options.
First, instead of creating foreign keys in the separate columns, keep ids in a column by casting them an array. This is easy to setup and very flexible way.
Second, which is a better way in my opinion, using proper eloquent relationships like following:
The structure you want to achieve is a form of many-to-many relationship.
You need 3 tables: items, associations, association_item.
// Models/Item.php
public function associations()
{
return $this->belongsToMany(Association::class);
}
// Models\Association.php
public function items()
{
return $this->belongsToMany(Item::class);
}
public function additions()
{
return $this->hasMany($this, 'parent_id', 'id');
}
// Migrations
Schema::create('items', function (Blueprint $table) {
$table->increments('id');
// some fields
$table->timestamps();
});
Schema::create('associations', function (Blueprint $table) {
$table->increments('id');
// some fields
$table->foreingId('parent_id')->nullable()->costrained('assosiations')
$table->timestamps();
});
Schema::create('association_item', function (Blueprint $table) {
$table->increments('id');
$table->foreignId('item_id');
$table->foreingId('association_id');
$table->timestamps();
});
Related
SQLSTATE[22007]: Invalid datetime format: 1366 Incorrect integer value: 'Earphone' for column inventory.products.category_id at row 1 .
My product name is string type and it's join with the categories table. But the category id is integer type.
Query Code:
public function index()
{
//
$products = DB::table('products')
->join('categories','products.category_id','categories.id')
->join('suppliers','products.supplier_id','suppliers.id')
->select('categories.category_name','suppliers.name','products.*')
->orderBy('products.id','DESC')->get();
;
return response()->json($products);
}
This is my products table
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->integer('category_id');
$table->string('product_name');
$table->string('product_code');
$table->string('root')->nullable();
$table->string('buying_price')->nullable();
$table->string('selling_price');
$table->integer('supplier_id');
$table->string('buying_date');
$table->string('image')->nullable();
$table->string('product_quantity');
$table->timestamps();
});
This is category table :
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('category_name');
$table->timestamps();
});
}
Please fix me where am I doing wrong?
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->bigInteger('category_id')->unsigned();
$table->string('product_name');
$table->string('product_code');
$table->string('root')->nullable();
$table->string('buying_price')->nullable();
$table->string('selling_price');
$table->integer('supplier_id');
$table->string('buying_date');
$table->string('image')->nullable();
$table->string('product_quantity');
$table->timestamps();
});
$table->foreign("category_id")->references("id")->on("categories");
////////////////// end migration ////////////////////////////
$products = DB::table('products')
->join('categories','products.category_id','=','categories.id')
->join('suppliers','products.supplier_id','=','suppliers.id')
->select('categories.category_name','suppliers.name','products.*')
->orderBy('products.id','=','DESC')->get();
You should edit code like that. After i hope it is work.
Make id column autoincrement in your migrations as bellow
$table->bigIncrements('id');
Here are my tables
Schema::create('badge_user', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
$table->foreignId('badge_id')->references('id')->on('badges')->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
$table->softDeletes();
});
Schema::create('badges', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->string('image')->nullable();
$table->integer('condition');
$table->timestamps();
$table->softDeletes();
});
Here are relationships
In BagdeUser modal
public function badge()
{
return $this->hasMany(Badge::class);
}
In Badge modal
public function badgeUser()
{
return $this->belongsTo(BadgeUser::class , 'badge_id');
}
In my resource
I have fetched all the data from the badge_user table and passed it in the resource
public function toArray($request)
{
return [
'badges' => new BadgeResource($this->badge),
];
}
BadeResource
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'image' => new MediaResource($this->getMedia('badge')->first()),
'condition' => $this->condition,
];
While fetching data o got this
Column not found: 1054 Unknown column 'badges.badge_user_id' in 'where clause' (SQL: select * from `badges` where `badges`.`badge_user_id` = 1 and `badges`.`badge_user_id` is not null and `badges`.`deleted_at` is null)
Now I want the badges associate with the user
The problem is that in your badge_user migration, you create foreign key badge_id which would mean that there is a relation Badge User N:1 Badge
But in your models you assign that BadgeUser has many Badges and Badge belongs to BadgeUser (which is Badge User 1:N Badge)
That is why laravel is looking for badge_user_id in query, because you defined the relationship the other way around.
Still tho you are probably doing M:N relations which you don't need to do manually.
You should use something like this (from Laravel docs)
return $this->belongsToMany(Role::class);
Hello guys i am stuck with problem with 1 course. This is the error which i get :
Illuminate\Database\QueryException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'votables.question_id' in 'field list' (SQL: select `users`.*, `votables`.`question_id` as `pivot_question_id`, `votables`.`votable_id` as `pivot_votable_id`, `votables`.`votable_type` as `pivot_votable_type` from `users` inner join `votables` on `users`.`id` = `votables`.`votable_id` where `votables`.`question_id` in (2) and `votables`.`votable_type` = App\Models\User)
I made Polymorphic Relationship from User Model , Question Model and Answer Model into table "votables"
**User DB migration:**
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Question DB migration:
Schema::create('questions', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->text('body');
$table->unsignedInteger('views')->default(0);
$table->unsignedInteger('answers')->default(0);
$table->integer('votes_count')->default(0);
$table->unsignedInteger('best_answer_id')->nullable();
$table->unsignedBigInteger('user_id');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
});
and Votables DB migration:
Schema::create('votables', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('votable_id');
$table->string('votable_type');
$table->tinyInteger('vote')->comment('-1: down vote, 1: up vote');
$table->timestamps();
$table->unique(['user_id', 'votable_id', 'votable_type']);
});
My route:
Route::post('/questions/{question}/vote', VoteQuestionController::class);
VoteQuestionController :
public function __invoke(Question $question){
$vote = (int) request()->vote;
auth()->user()->voteQuestion($question, $vote);
return back();
}
and Models - User
public function voteQuestions(){
return $this->morphedByMany(Question::class, 'votable');
}
public function voteAnswers(){
return $this->morphedByMany(Answer::class, 'votable');
}
public function voteQuestion(Question $question, $vote){
$voteQuestions = $this->voteQuestions();
if($voteQuestions->where('votable_id', $question->id)->exists()){
$voteQuestions->updateExistingPivot($question, ['vote' => $vote]);
}
else{
$voteQuestions->attach($question, ['vote' => $vote]);
}
$question->load('votes');
$downVotes = (int) $question->downVotes()->sum('vote');
$upVotes = (int) $question->upVotes()->sum('vote');
dd($upVotes);
$question->votes_count = $upVotes + $downVotes;
$question->save();
}
and Question model:
public function votes(){
return $this->morphedByMany(User::class, 'votable');
}
public function upVotes(){
return $this->votes()->wherePivot('vote', 1);
}
public function downVotes(){
return $this->votes()->wherePivot('vote', -1);
}
So after clicking the button from auth user to vote some question i get in db:
https://prnt.sc/wnbak9
But in questions table they didnt count and i get that error after click. Some suggestions?
I have referred all the other questions asked and did what they have told. Still i cant get rid of default_value error. I have added multiple connections. So i have 3 databases : Users , companya , companyb.
Company-A and Company-B has same structure.
Stocks have tag_no as primary key and i have specified it in model too.
Inside Stock model I have created a constructor to dynamically switch models based on users company.
Even after all this i keep getting this error.
I tried changing strict to false inside database.php but.. all the entries are showing value 0. So I stopped trying that.
So what can i do to solve this. Please help!
Below is my schemas:
For Users:
Schema::connection('mysql')->create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('company')->default('companya');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->string('user_type',50)->default('user');
$table->rememberToken();
$table->timestamps();
});
For company-A and company-B:
Schema::connection('companya')->create('stocks', function (Blueprint $table) {
$table->string('tag_no')->index();
$table->string('stock_type');
$table->timestamps();
});
Here is my Stock Model:
class Stock extends Model
{
protected $primaryKey = 'tag_no';
public $incrementing = false;
protected $fillable = [
'tag_no',
'stock_type',
];
public function __construct() {
if ( Auth::check() ) {
$this->connection = Auth::user()->company;
}
}
}
Code for store function:
public function store(Request $request)
{
if(Auth::check()){
if (Stock::where('tag_no','=',$request->input('tag_no'))->exists()) {
return back()->withInput()->with('errors', 'Tag number already used!');
}
$stock = Stock::create([
'tag_no' => $request->input('tag_no'),
'stock_type' => $request->input('stock_type'),
]);
}
if($stock){
return redirect()->route('stocks.index', ['stocks'=> $stock->tag_no])
->with('success' , 'Stock created successfully');
}
return back()->withInput()->with('errors', 'Error creating new Stock');
}
Just changed create to insert and removed stocks parameter.
public function store(Request $request)
{
if(Auth::check()){
if (Stock::where('tag_no','=',$request->input('tag_no'))->exists()) {
return back()->withInput()->with('errors', 'Tag number already used!');
}
$stock = Stock::insert([
'tag_no' => $request->input('tag_no'),
'stock_type' => $request->input('stock_type'),
]);
}
if($stock){
return redirect()->route('stocks.index')
->with('success' , 'Stock created successfully');
}
return back()->withInput()->with('errors', 'Error creating new Stock');
}
I am trying to seed a many-to-many join table of quests and npcs in those quests... a quest can have many npcs, and an NPC can be used in many quests. I am using Laravel 5.
When seeding the Quest table, I'm also seeding the join table, but am getting the following error:
Base table or view not found: 1146 Table 'clg_local.npc_quest' doesn't exist
Create Quest and Quest_NPC table:
public function up()
{
/*
* Create quests table
*/
Schema::create('quests', function(Blueprint $table)
{
$table->increments('id');
$table->string('quest_name')->nullable();
$table->unsignedInteger('reward_xp')->nullable();
$table->string('reward_items')->nullable();
$table->unsignedInteger('reward_money')->nullable();
});
/*
* Create quests_npcs join table
*/
Schema::create('quest_npc', function(Blueprint $table)
{
$table->increments('id');
$table->unsignedInteger('quest_id')->nullable();
$table->unsignedInteger('npc_id')->nullable();
});
In a separate create, I specify my relations:
Schema::table('quest_npc', function(Blueprint $table)
{
$table->foreign('quest_id')->references('id')->on('quests')->onDelete('cascade');
$table->foreign('npc_id')->references('id')->on('npcs')->onDelete('cascade');
});
Clearly I am creating a quest_npc table, but it's looking for a npc_quest table?
Quest seeder:
public function run()
{
Eloquent::unguard();
$quests = $this->createQuests();
$npcs = Npc::all()->toArray();
foreach ($quests as $quest) {
$quest->npcs()->attach($npcs[rand(0, count($npcs) - 1)]['id']);
}
private function createQuests()
{
Quest::unguard();
$quests = [];
foreach (
[
[
'quest_name' => 'Quest 1',
'reward_xp' => 200,
'reward_items' => null,
'reward_money' => 200,
], ...
NPC model:
public function npcs()
{
return $this->belongsToMany(Npc::class);
}
Quest model:
public function quests()
{
return $this->belongsToMany(Quest::class);
}
From the documentation, Laravel 'assumes' the table name to be
derived from the alphabetical order of the related model names
So in your case, that's the "why".
You can add a second parameter to your belongsToMany call to indicate the name you would like to use. For example:
public function quests()
{
return $this->belongsToMany(Quest::class, 'quest_npc');
}
Do the above for both relationships
In my opinion, stick to the convention, unless you need a reason not to.