Laravel 5.4 many to many relationships with foreign key - php

i'm using a data table with name auct_lots_full for my Lot.php model, where primary key is lot_id, in order everything to work i used Sofa/Eloquence extension, Mappable. So this is my model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Sofa\Eloquence\Eloquence;
use Sofa\Eloquence\Mappable;
class Lot extends Model
{
use Eloquence, Mappable;
protected $table = 'auct_lots_full';
protected $maps =[
'id' => 'lot_id',
];
public function scopeFilter($query, QueryFilter $filters)
{
return $filters->apply($query);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
But he problem is that in some cases it keeps looking for id column as primary key. For example in LotsController.php i have this problem here :
public function show($id)
{
$lot = Lot::find($id);
return view('lots.show')->withLot($lot);
}
But i fix this problem with this solution:
public function show($id)
{
$lot = Lot::where('lot_id', $id)->first();
return view('lots.show')->withLot($lot);
}
But i understand that is just a solution for only this function...
So the same problem i have in CommentsController.php:
public function show()
{
$comments = Comment::orderBy('id', 'desc')->paginate(30);
return view('comments.browse', compact('comments'));
}
And i don't know how to fix it. Could any one explain me why is this happening? Is there a better way than use an extension? How i can fix this error in CommentsCotroller.php ?
This is the Comment.php model:
<?php
namespace App;
class Comment extends Model
{
public function lot()
{
return $this->belongsTo(Lot::class);
}
public function User()
{
return $this->belongsTo(User::class);
}
}

There is a primaryKey variable in your Model file which is id by default.
/**
* The primary key for the model.
*
* #var string
*/
protected $primaryKey = 'id';
If you override this variable in Lot model file. So your primary key will be lot_id instead of id as in default. Simply add this;
protected $primaryKey = 'lot_id';

So actually i find a proper way to do it with out Sofa/Eloquence extension, using not only foreign key but also a local key in many to many relationship. So this is the new code:
so for Lot.php i did this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Lot extends Model
{
protected $table = 'auct_lots_full';
protected $primaryKey = 'lot_id';
public function scopeFilter($query, QueryFilter $filters)
{
return $filters->apply($query);
}
public function comments()
{
return $this->hasMany(Comment::class,'lot_id', 'lot_id');
}
}
Than i did same for the Comment.php model:
<?php
namespace App;
class Comment extends Model
{
public function lot()
{
return $this->belongsTo(Lot::class, 'lot_id', 'lot_id');
}
public function User()
{
return $this->belongsTo(User::class);
}
}
So what we see above, in Lot.php model, function comments i pass foreignKey: 'lot_id' in auct_lots_full table and localKey 'lot_id' in comments table witch refers to the auct_lots_full table. In Comment.php model wi did the same but in case instead of localKey it is ownerKey. Im a bad at explaining so i will attach some images to make sense.
Lot.php
Comment.php

Related

Slug problems show with laravel

I have model:
class Header extends Model
{
use HasFactory;
public function getRouteKeyName()
{
return 'slug';
}
}
my controller:
public function show($id)
{
$headers = DB::table('headers')->find($id);
$blocks = DB::table('blocks')->where('header_id', $id)->get();
return view('test', compact('headers', 'blocks'));
}
my route:
Route::get('/{id}', [MainController::class, 'show'])->name('show');
but I can't show slug, I see localhost:8000/id
error: Attempt to read property "id" on null
You are using getRouteKeyName which is useful for Route-Key binding. But your route is not set up that way.
It also does not help you with the find() method in the Model.
Also, you are not using your model in your DB call. Any methods or properties defined in your model will therefore not be used.
And you should set up relationships to get related data.
Respecting your current route, you should do something like this:
class Header extends Model
{
use HasFactory;
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'slug';
// ^-- this is what you use to tell Model what column to use for find()
// only use this if you do route-model binding
public function getRouteKeyName()
{
return 'slug';
}
// relationship to find all blocks that belong to this header_id
public function blocks()
{
return $this->hasMany(\App\Model\Blocks::class);
}
}
Then for the DB Call:
public function show($id)
{
$header = Headers::find($id);
$blocks = $header->blocks ?? [];
return view('test', compact('header', 'blocks'));
}

Call to undefined method App\Models\Comment::comments()

I wanted to add comment to every post I make but I keep on getting errors.
Comment Controller:
public function store(Request $request)
{
$comments = new Comment;
$comments->body =$request->get('comment_body');
$comments->user()->associate($request->user());
$blogs = Comment::find(1);
$blogs->comments()->save($comments);
return back();
}
Comment Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
use HasFactory;
protected $guarded =[];
public function blog()
{
return $this->belongsTo(Blog::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
Blog Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model
{
use HasFactory;
protected $fillable = ['user_id' , 'blog_category_id' , 'title' , 'description'];
public function user()
{
return $this->belongsTo(user::class);
}
public function blogcategory()
{
return $this->hasOne(BlogCategory::class)->withDefault(function($user , $post){
$user->name = "Author";
});
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
You are using the wrong model; the Blog model has the comments relationship not the Comment model:
$blog = Blog::find(...);
$blog->comments()->save(...);
Update:
You seem to want to be using a Polymorphic relationship it would seem based on the structure of your comments table since you have the fields commentable_id and commentable_type. If you check the documentation for the Polymorphic One to Many relationship this is the same as the example in the documentation:
Blog model:
public function comments()
{
return $this->morphMany(Comment::class, 'commentable');
}
Comment model:
public function commentable()
{
return $this->morphTo();
}
Laravel 8.x Docs - Eloquent - Relationships - Polymorphic Relationships - One to Many
Having said that, your Comment model doesn't look like you wanted to use a polymorphic relationship since you specifically had a blog relationship method. If you do not have more than 1 entity that needs to be related to Comment I would not be using a polymorphic relationship.

Problem with Laravel Eloquent - relation not working

I'am beginner in Laravel. I have project in Laravel 5.8.
I have User model:
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
use psCMS\Presenters\UserPresenter;
use scopeActiveTrait;
public static $roles = [];
public $dates = ['last_activity'];
// ...
public function scopeHistory()
{
return $this->hasMany('App\UserLoginHistory');
}
// ...
}
and UserLoginHistory:
class UserLoginHistory extends Model
{
protected $quarded = ['id'];
public $timestamps = false;
protected $fillable = ['user_id', 'date_time', 'ip'];
public function user()
{
return $this->belongsTo('App\User');
}
}
I want show user login history by this code:
User::history()->where('id', $idAdmin)->orderBy('id', 'desc')->paginate(25);
but it's not working.
This function not working - I haven't got results.
How can I fixed it?
First of all, you are defining your relationship as a scope (prefixing the relationship with the scope keyword). Try updating your model relationship to this:
public function history()
{
return $this->hasMany('App\UserLoginHistory');
}
Then, given your query, it seems that you want to get all the UserLoginHistory
records for a given User. You could accomplish this in two ways (at least).
From the UserLoginHistory model itself, constraining the query by the foreign key value:
$userId = auth()->id(); // get the user ID here.
$results = UserLoginHistory::where('user_id', $userId)->paginate(15);
// ^^^^^^^ your FK column name
From the User model using your defined relationship:
$userId = auth()->id(); // get the user ID here.
$results = User::find($userId)->history;
The downside of the second approach is that you'll need to paginate the results manually.
in your User model you should define your relation by this way :
public function history()
{
return $this->hasMany('App\UserLoginHistory');
}
then if you would like to select with history model you can do that with WhereHas() method :
User::whereHas(['history'=>function($q) use ($idAdmin) {
$q->where('id',$idAdmin)
}])->orderBy('id', 'desc')->paginate(25);
You must be do this changes
public function history()
{
return $this->hasMany('App\UserLoginHistory');
}
usage
$user = User::find($idAdmin);
$userHistories = $user->history()->latest()->paginate(25);
or get user with all history
User::with('history')->find($idAdmin);
// Post model
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
}
// Category model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
}

Laravel Eloquent: 3 table relationship

I'm new to Laravel-eloquent, I would like to translate this SQL to Eloquent mode:
select
fl.id, fut.id, fut.firebase_topic_id, ft.id, fl.created_at
from
firebase_logs fl,
firebase_user_topics fut,
firebase_topics ft
where
fl.id = fut.firebase_log_id
and
fut.firebase_topic_id = ft.id
and
fl.created_at between '2019-01-09 16:33:39' and '2019-01-09 16:33:41'
and
ft.id = 1
order by fl.created_at asc
Where:
Firebase_logs.id (1) -> Firebase_user_topics.firebase_log_id (N)
and
Firenase_user_topics.firebase_topic_id (N) -> Firebase_topics.id (1)
FirebaseLog.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class FirebaseLog extends Model
{
public $incrementing = false;
protected $primaryKey = 'id';
public function user_topics() {
//return $this->hasManyThrough(FirebaseTopics::class, FirebaseUserTopics::class);
return $this->hasMany(FirebaseUserTopics::class);
}
}
FirebaseUserTopics.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class FirebaseUserTopics extends Model
{
protected $table = 'firebase_user_topics';
public function log()
{
return $this->belongsTo(FirebaseLog::class);
}
public function topic()
{
return $this->belongsTo(FirebaseTopics::class);
}
}
FirebaseTopics.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class FirebaseTopics extends Model
{
protected $table = 'firebase_topics';
public function user_topics()
{
return $this->hasMany(FirebaseUserTopics, 'firebase_user_topics');
}
}
My Controller, works fine with this:
$a = FirebaseLog::with('user_topics')->whereBetween('created_at', array('2019-01-09 16:33:39', '2019-01-09 16:33:41'))->get();
return $a;
But I don't know how to connect to FirebaseTopics to continue building the code, some help will be appreciated.
EDITED ANSWER!
The solution of your problem is use the hasOne relation instead of belongsTo in your FirebaseUserTopics model. It must be following;
public function topic()
{
return $this->hasOne(FirebaseTopics::class, 'id', 'firebase_topic_id');
}
Because your FirebaseTopics model has not a relation with FirebaseUserTopics model. The "belongsTo" (that uses to make reverse a relation) search firebase_topic_id field in the firebase_topics table but this field has no in the firebase_topics table. That's why, you must be make to relation directly, not reverse.

Eloquent model relationship for intermediate table

Consider the following table structure:
user table
id
name
lang_region_id
lang_region table
id
lang_id
region_id
lang table
id
name
region table
id
name
Fairly new to the Laravel framework, but trying to setup Eloquent models and relationships to an existing database. I want to establish the relationship between my user model and the lang and region models. The lang_region table defines what language and region combinations are available and then we can link each user to a valid combination.
I have read through the Laravel documentation several times looking for the proper relationship type, but is seems that the Many to Many and Has Many Through relationships are close, but since our user.id isn't used in the intermediate table I may be out of luck.
Sorry for the amateur question, but just getting used to Laravel and ORMs in general.
I would use the lang_region table as both a pivot table and a regular table with its own model.
class LangRegion extends model
{
protected $table = 'lang_region';
public function language()
{
return $this->belongsTo(Language::class, 'lang_id');
}
public function region()
{
return $this->belongsTo(Region::class);
}
public function users()
{
return $this->hasMany(User::class);
}
}
class User extends model
{
protected $table = 'user';
public function langRegion()
{
return $this->belongsTo(LangRegion::class);
}
}
class Language extends model
{
protected $table = 'lang';
public function regions()
{
$this->belongsToMany(Region::class, 'lang_region', 'lang_id', 'region_id');
}
public function users()
{
$this->hasManyThrough(User::class, LangRegion::class, 'lang_id', 'lang_region_id');
}
}
class Region extends model
{
protected $table = 'region';
public function languages()
{
$this->belongsToMany(Language::class, 'lang_region', 'region_id', 'lang_id');
}
public function users()
{
$this->hasManyThrough(User::class, LangRegion::class, 'region_id', 'lang_region_id');
}
}
If I understand what you want correctly:
class User extends Model {
private function lang_region() {
return $this->hasOne(LangRegion::class)
}
public function lang() {
return $this->lang_region()->lang();
}
public function region() {
return $this->lang_region()->region();
}
}
class LangRegion extends Model {
public function lang() {
return $this->belongsTo(Lang::class);
}
public function region() {
return $this->belongsTo(Region::class);
}
}

Categories