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.
Related
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();
});
This question is similar to this question
I haven't changed the default autoIncrement from the table migration, however I noticed i couldn't get a model from the ID for a specific row. For the other rows it works fine. I cleared cache thinking it was a cache issue, but seems it is not.
Behaviour
I got records 1,..., 58, 59, 60
When i select a model
$object = Post::find(59);
// $object returns null but record exists
However i added another record via the app to check if the behaviour is the same, and the record from 60 is not null and it is the expected behaviour. Has anyone encountered this? If so what would be the best approach to overcome this.
I am using XAMPP v8.0.8 on Windows
Edit:
Post Model
class Post extends Model
{
use HasFactory,Searchable,SoftDeletes;
protected $fillable = [
'hash_id','user_id','location','subjects','request_type'
];
protected $casts = [
'location' => 'array',
'subjects' => 'array'
];
public function User()
{
return $this->belongsTo('App\Models\User');
}
public function searchableAs()
{
return 'posts';
}
}
Migration file
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('hash_id')->unique();
$table->integer('user_id');
$table->json('location');
$table->json('subjects');
$table->string('request_type');
$table->timestamps();
$table->softDeletes();
});
}
Assuming from soft deletes this happens if the record is deleted. Try looking in the deleted_at field on database.
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);
I want to display all posts which like the user. OK. I can use this:
$user = User::where('slug', $user->slug)
->first();
dd($user->likes);
But it doesn't what I want to do. Which any post have to be accept by moderator (->where('accept', 1)) and orderign (->orderBy('created_at', 'desc')).
Who know how I can do that?
Currently I have 2 models. My relationships:
//Post
public function likes(){
return $this->hasMany('App\Like');
}
//Likes
public function post(){
return $this->belongsTo('App\Post');
}
//migrate of likes look like this
Schema::create('likes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('user_id');
$table->integer('post_id');
$table->timestamps();
});
How I can solve my problem?
You could set up an M:N relationship between User and Post using Likes as pivot.
# User model
public function likes()
{
return $this->hasMany(Likes::class, 'user_id');
}
public function liked_posts()
{
return $this->belongsToMany(Post::class, 'likes', 'user_id', 'post_id');
}
# Likes model
public function post()
{
return $this->belongsTo(Post::class);
}
You could set it up like you have, User has many Likes belongs to Post.
// Using only likes and Likes's post relationship
$user = User::with(['likes.post' => function ($posts) {
$posts->where('accept', 1)->orderBy('created_at', 'desc');
}])->where('slug', $slug)->first();
Or you could use the M:N relationship.
// Using the liked_posts relationship
$user = User::with(['liked_posts' => function ($posts) {
$posts->where('accept', 1)->orderBy('created_at', 'desc');
}])->where('slug', $slug)->first();
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');
}