show last post from each category - laravel

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

Related

Laravel 8 : SoftDeletes not updated when deleting a user linked to a form

I have a problem on Laravel 8 when I delete a user I have my 'deleted_at' which is updated in my 'user' table but not the 'deleted_at' of my 'forms' table because I want to delete the forms linked to this user otherwise I have an error because I display his info when he does not exist anymore.
How do I fix this problem please?
I have used the soft delete in the Models
and the 'deleted_at' is updated when I delete the form.
users migration :
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('firstname');
$table->string('lastname');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->foreignId('current_team_id')->nullable()->onDelete('cascade');
$table->string('profile_photo_path', 2048)->nullable();
$table->timestamps();
$table->foreignId('role_id')->references('id')->on('roles')->onDelete('cascade');
$table->softDeletes();
});
}
public function down()
{
Schema::dropIfExists('users', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
}
forms migration :
public function up()
{
Schema::create('forms', function (Blueprint $table) {
$table->id();
$table->string('title', 100);
$table->text('message');
$table->datetime('date');
$table->string('color');
$table->softDeletes();
$table->timestamps();
});
}
public function down()
{
// Schema::dropIfExists('forms');
Schema::table('forms', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
}
add user to forms migration :
public function up()
{
Schema::table('forms', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
public function down()
{
Schema::table('forms', function (Blueprint $table) {
$table->dropForeign('user_id')->onDelete('cascade');
});
}
Soft delete won't work on cascading foreign keys. Cascading foreign keys is a feature of sql servers and soft delete is a feature of laravel and needs the laravel context to work.
When you delete it, for the soft deletes to work, you need to call delete on each model of the relation. This is quite easy with collections and higher order functions.
{
$user = User::firstOrFail($id);
$user->forms->each->delete();
$user->delete();
...
}
Thank you very much mrhn,
Thanks to you I have learned a lot!
For those which want the function in the controller which thus makes it possible to remove the user to which belongs thus the id and one thus removes also what is related to him in my case a forms (function in the Models for the cardinalities between entity) :
public function destroy($id)
{
// $users = User::findOrFail($id);
// $users->delete();
$user = User::findOrFail($id);
$user->forms->each->delete();
$user->delete();
return redirect()->route('admin');
}
findOrFail and not firstOrFail ^^'

get all tags from several posts at the same time

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();

Property [roles] does not exist on this collection instance. in a many-to-many relationship

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;
}

Trying to get property of non-object when i try to $blog->user->name

in my model user
public function blogs(){
return $this->hasMany('App\Blog');
}
in my model blog
public function user(){
return $this->belongsTo('App\User','user_id');
}
in my BlogController
public function show($id)
{
$blog = Blog::find($id);
dd($blog->user->name);
return view('admin.pages.blogs.show',compact('blog'));
}
database table user ( id,role_id,name)
if role_id = 1(admin) then result $blog->user->name is null
if role_id = 2(author) then result $blog->user->name is name of user
how can i fix when role_id = 1
You need to remove user_id from Blog model.
public function user()
{
return $this->belongsTo(User::class);
}
UPD. In any case role_id does not matter. So you need to make sure DB contains related records. For example:
blogs:
id user_id text
1 123 '...'
users:
id name
123 'Linh'
First of all you change blogs users and roles migration.
blogs migration
Schema::create('blogs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('title');
$table->string('slug')->unique();
$table->string('image');
$table->string('body');
$table->tinyInteger('status')->default(0);
$table->tinyInteger('is_approved')->default(0);
$table->integer('view_count')->default(0);
$table->timestamps();
});
users migration
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('role_id')->default(2);
$table->foreign('role_id')->references('id')->on('roles');
$table->string('name');
$table->string('username')->unique();
$table->string('email')->unique();
$table->string('password');
$table->string('image')->default('default.png');
$table->text('about')->nullable();
$table->rememberToken();
$table->timestamps();
});
roles migration
Schema::create('roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('slug')->unique();
$table->timestamps();
});
User model
public function blogs(){
return $this->hasMany('App\Blog');
}
Blog model
public function user(){
return $this->belongsTo('App\User');
}
BlogController
public function show($id)
{
$blog = Blog::find($id);
dd($blog->user->name);//check
return view('admin.pages.blogs.show',compact('blog'));
}

BadMethodCallException: Trying to list all partners with the categories laravel

I'm experiencing the following:
Goal: I would like to list all partners and the categories they belong to. Basically, it's a many to many relationship.
Below is the code:
Partner Categories Table Migration
public function up()
{
Schema::create('partcats', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('partcatnameP')->unique();
$table->unsignedBigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
Partners Table Migration
public function up()
{
Schema::create('partners', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('partnername');
$table->string('regnumber')->unique();
$table->unsignedBigInteger('activestatus_id')->unsigned();
$table->foreign('activestatus_id')->references('id')->on('activestatuses');
$table->unsignedBigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
Partner_Category Migration
public function up()
{
Schema::create('partner_partcat', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('partner_id')->unsigned();
$table->foreign('partner_id')->references('id')->on('partners')->onDelete('cascade');
$table->unsignedBigInteger('partcat_id')->unsigned();
$table->foreign('partcat_id')->references('id')->on('partcats')->onDelete('cascade');
$table->timestamps();
});
}
Models are as shown below:
Partcat Model
public function partners()
{
return $this->belongsToMany('App\Partcat','partner_partcat');
}
Partner Model
public function partcats()
{
return $this->belongsToMany('App\Partcat','partner_partcat');
}
and the Partners Controller is as shown below:
public function index()
{
//
$partners = Partner::all()->partcats();
// dd(Partner::all()->partcats());
return view('partners.index',['partners'=>$partners]);
}
This is where I'm trying to retrieve the list of partners and its related categories. However, I get a BadMethod call error.
You can use the following method
$partners = Partner::with('partcats')->get();
https://laravel.com/docs/5.6/eloquent-relationships#eager-loading
A many to many pivot table typically has the id for both tables it is relating.
The Partner_Category migration you have posted only seems to contain a partner_id. You may need to add in the category_id.
public function up()
{
Schema::create('partner_partcat', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('partner_id')->unsigned();
$table->unsignedBigInteger('partcat_id')->unsigned();
$table->timestamps();
$table->foreign('partner_id')->references('id')->on('partners')->onDelete('cascade');
$table->foreign('partcat_id')->references('id')->on('partcats')->onDelete('cascade');
});
}

Resources