I have a set that has a list of group and each group has a list of attributes like this
//sets
Schema::create('sets', function (Blueprint $table) {
$table->id();
$table->string('name');
});
//groups
Schema::create('groups', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->foreignId('set_id')->constrained('sets')->onDelete('cascade');
});
//attributes
Schema::create('attributes', function (Blueprint $table) {
$table->id();
$table->string('name');
});
//set_group_attributes
Schema::create('set_group_attributes', function (Blueprint $table) {
$table->foreignId('set_id')->constrained('sets')->onDelete('cascade');
$table->foreignId('group_id')->constrained('groups')->onDelete('cascade');
$table->foreignId('attribute_id')->constrained('attributes')->onDelete('cascade');
$table->integer('position');
$table->unique(['set_id', 'attribute_id']);
});
I need to save the set with groups and attributes, this is my code :
$set = Set::create(['name' => $request->name]); ---> save the set
$set->groups()->createMany($request->groups); ---> save the group
//set model
public function groups(): HasMany
{
return $this->hasMany(Group::class, 'set_id','id');
}
My question is how to save the attributes with laravel eloquent?
Here we can use attach like in Docs with belongsToMany
//group model
/**
* #return BelongsToMany
*/
public function attributes(): BelongsToMany
{
return $this->belongsToMany(Attribute::class, 'set_group_attributes', 'group_id', 'attribute_id')->withPivot('position');
}
// save attributes of groups
foreach ($attributes as $attribute) {
$group->attributes()->attach($attribute['id'], ['set_id' => $model->id, 'position' => $attribute['position']]);
}
Related
I need to create a query that get all tags from an array of posts.in a many-to-many polymorphic relationship between tags and posts
TAG MODEL
class Tag extends Model
{
use HasFactory;
protected $guarded = ['id'];
//
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
}
POST MODEL
class Post extends Model
{
use HasFactory;
protected $guarded = ['id'];
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
TAG MIGRATION
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
TAGGABLE MIGRATION
public function up()
{
Schema::create('taggables', function (Blueprint $table) {
$table->id();
$table->bigInteger('tag_id')->unsigned();
$table->morphs('taggable');
$table->foreign('tag_id')->references('id')->on('tags')
->onDelete('cascade')
->onUpdate('cascade');
});
}
POST MIGRATION
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description');
// 1 borrador, 2 revision, 3 publicado, 4 caducado
$table->enum('status', [Post::BORRADOR, Post::REVISION, Post::PUBLICADO, Post::CADUCADO]);
// Para diferenciar entre publicaciones del Sistema (Admin = 1) o de usuarios normales (USERS = 2)
$table->enum('type', [Post::ADMIN, Post::USERS]);
$table->boolean('atemporal');
$table->string('slug')->unique();
$table->unsignedBigInteger('user_id')->nullable();
$table->unsignedBigInteger('survey_id')->nullable();
$table->foreign('user_id')->references('id')->on('users')->onDelete('set null');
$table->foreign('survey_id')->references('id')->on('surveys');
$table->timestamps();
});
CATEGORIES MIGRATION
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->unsignedBigInteger('parent_id')->nullable();
$table->string('slug');
$table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
PIVOT TABLE CATEGORY_POST
Schema::create('category_post', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('category_id');
$table->unsignedBigInteger('post_id');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->timestamps();
});
RELATIONSHIP POST
public function categories()
{
return $this->belongsToMany(Category::class);
}
RELATIONSHIP CATEGORY
public function posts()
{
return $this->belongsToMany(Post::class);
}
I have tried this but I can't get it to work
$posts = Post::whereHas('categories', function($query) {
$query->whereIn('category_id', [$this->categoriaTags]);
})->get();
// Here I get the list of posts from which I want to get their tags, this is OK.
//But then I can't get the right query to get the tags.
$tags = Tag::whereHasMorph('posts', function($query) use($posts){
$query->where('tag_id', $posts);
})->get();
Any suggestions? Thank you
You are close, but you are querying the wrong column, and using the wrong builder method. You want:
$tags = Tag::whereHasMorph('posts', function ($query) use ($posts) {
$query->whereIn('id', $posts->pluck('id'));
})->get();
I follow tutorial from laravel documentation but it seems the tutorial not complete to explain argument morphToMany to explicit determine what the function should point to.
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'tagables.tagables_id' in 'field list' (SQL: select tags.*,
tagables.tagables_id as pivot_tagables_id,
tagables.tag_tag_id as pivot_tag_tag_id,
tagables.tagables_type as pivot_tagables_type from tags inner
join tagables on tags.tag_id = tagables.tag_tag_id where
tagables.tagables_id = 1 and tagables.tagables_type =
App\Models\Comic)
media table
Schema::create('media', function (Blueprint $table) {
$table->mediumIncrements('media_id)->nullable(false);
$table->string('title', 255);
});
tags table // one row inside tag ( walking )
Schema::create('tags', function (Blueprint $table) {
$table->mediumIncrements('tag_id');
$table->string('tag_name', 255);
});
tagables table
Schema::create('tagables', function (Blueprint $table) {
$table->unsignedMediumInteger('tag_id')->nullable(false);
$table->unsignedMediumInteger('tagable_id')->nullable(false);
$table->string('tagable_type', 255)->nullable(false);
});
comic model
public function tags()
{
return $this->morphToMany(Tag::class, 'tagable');
}
comic controller
// insert new comic
$comic = Comic::create([
'title' => 'Doraemon',
]);
// Insert into tagables table with current comic id and bind to tag id 1
which is walking
$comic->tags->create([
'tag_id' => 1
]);
it succes to insert into media but failed to insert into tagables table.
I found some mistakes in your code. Please try to rewrite this code. There is a working example of your code. I have checked it for you
2021_04_10_073813_create_media_table.php
Schema::create('media', function (Blueprint $table) {
$table->id();
$table->string('name', 255);
$table->timestamps();
});
2021_04_10_073837_create_tags_table.php
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name', 255);
$table->timestamps();
});
2021_04_10_073856_create_taggables_table.php
Schema::create('taggables', function (Blueprint $table) {
$table->id();
$table->unsignedMediumInteger('tag_id')->nullable(false);
$table->unsignedMediumInteger('taggable_id')->nullable(false);
$table->string('taggable_type');
$table->timestamps();
});
class Media extends Model
{
protected $guarded = [];
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
class Tag extends Model
{
protected $guarded = [];
public function medias()
{
return $this->morphedByMany(Media::class, 'taggable');
}
}
And finally in a some Controller
$media = Media::create([
'name' => 'media name1',
]);
$tag = $media->tags()->create([
'name' => 'tag name1',
]);
Hello I am learning relationship many to many I read the official documentation and use the conventions,
but I can't make the relation many to many I get the error that the property does not exist.
how can I solve that?
Migrations
Schema::create('role_user', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
$table->foreignId('role_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
}
User
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();
});
}
Roles
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Models:
User
public function roles(){
return $this->belongsToMany(role::class, 'role_user', 'user_id', 'role_id');
}
Role
public function users(){
return $this->belongsToMany(User::class, 'role_user','role_id','user_id');
}
query:
$v = User::get();
dd($v->roles);
$v = User::get(); returns a collection of users. If you get one user, for example, User::find(1) you will have access to the roles for this specific user.
Another option is
$users = User::with('roles')->get();
foreach ($users as $user) {
$userRoles = $user->roles;
}
I have two models Post and Category
// migration post
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('body');
$table->string('image');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories');
$table->timestamps();
});
}
// migration category
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
How can I display only the last post from each category in home page?
Hiren was close, but you need to go from the category since your post is owned by the category
$category->posts()->latest()->first();
Alternatively you could work backwards:
$post = Post::latest()->whereHas('category', function($q) use($category_id) {
return $q->where('id', $category_id);
})->first();
For this to work you'll need to define your model relationships:
Category Model needs this function:
public function posts()
{
return $this->hasMany(App\Post::class);
}
Post Model needs this function:
public function category()
{
return $this->belongsTo(App\Category::class);
}
To respond to Alexey Mezenin, we can just pass a callback to with() to define which posts we want to pull in for each category, performing the correct eager load.
Category::with(['posts' => function($q) {
return $q->latest()->first();
})->get();
An Eloquent solution for loading categories with latest post is to create an additional hasOne() relationship in the Category model:
public function latestPost()
{
return $this->hasOne(Post::class)->latest();
}
And then use eager loading:
Category::with('latestPost')->get();
This will generate just 2 queries to DB.
public function up()
{
Schema::create('news', function (Blueprint $table) {
$table->increments('id');
$table->string('slug')->unique();
$table->unsignedInteger('author_id');
$table->unsignedInteger('category_id');
$table->string('subject');
$table->text('short');
$table->text('content');
$table->integer('view')->default(0);
$table->integer('status')->default(0);
$table->string('image');
$table->timestamps();
$table->foreign('author_id')
->references('id')->on('users')
->onDelete('cascade');
// $table->foreign('category_id')
// ->references('id')->on('categories')
// ->onDelete('cascade');
});
// Schema::enableForeignKeyConstraints();
}
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->unique();
$table->timestamps();
});
}
in contoller:
$latestpostlist = News::whereIn('created_at',function($query){
$query->select(DB::raw('max(created_at)'))
->from('news')
->groupBy('category_id');
})->get();
in your case news will be post. this query worked for me
I have a polymorphic table called 'Item':
Schema::create('items', function(Blueprint $table) {
$table->increments('id');
$table->text('itemable_type')->nullable();
$table->string('itemable_id')->nullable();
$table->integer('subject_id')->nullable();
$table->integer('user_id')->nullable();
$table->integer('new')->nullable();
$table->integer('school')->nullable();
$table->string('private')->nullable();
$table->text('snippet')->nullable();
$table->string('elementSubject')->nullable();
$table->integer('follow_id')->nullable();
$table->timestamps();
});
Also have a table called 'Follow':
Schema::create('follows', function(Blueprint $table) {
$table->increments('id');
$table->integer('subject_id')->nullable();
$table->integer('teacher_id')->nullable();
$table->integer('user_id')->nullable();
$table->integer('effort')->nullable();
$table->timestamps();
});
Also have a table called 'Subject':
Schema::create('subjects', function(Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->integer('studentID')->nullable();
$table->integer('teacherID')->nullable();
$table->integer('schoolID')->nullable();
$table->integer('memberID')->nullable();
$table->string('private')->nullable();
$table->integer('creator')->nullable();
$table->softDeletes();
$table->timestamps();
});
They are linked together like this in my model:
class Follow extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function subjects()
{
return $this->hasMany('Subject');
}
I like to filter the 'Item' list based on the 'Subjects' the 'User' is following. What would my Eloquent look like?
I have this filtering on the 'School' but I want to filter it on what the user is 'Following'
$follows = Follow::where('user_id', Auth::user()->id)->get();
$items = Item::where('school', Auth::user()->school)
->where('private', 'false')
->orderBy('created_at', 'DESC')
->get();