Laravel Many-to-Many relationship not working - laravel

I'm facing a strange problem with Laravel Relations.
I'd like to access an event with many users (works perfect).
<?php
$event_with_user = Event::with('registered_users')->where('id', 253)->get();
dd($event_with_user);
And I'd like to access a user with all connected events:
<?php
$user_with_event = User::with('registered_events')->where('id', 1)->get();
dd($user_with_event);
Where I always receive this error:
Illuminate\Database\Eloquent\RelationNotFoundException
"Call to undefined relationship [registered_events] on model [App\User]."
I've checked the relations multiple times, but can't find a mistake. Does anyone else had that issue?
My Models
User.php
<?php
namespace App;
use App\Event;
use App\UserType;
use App\EventUser;
use App\Department;
use App\Evaluation;
use App\UserLocation;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'fname', 'lname', 'email', 'password', 'phone', 'email_verified_at', 'admin', 'user_type_id', 'last_login_at', 'last_login_ip', 'user_location_id', 'user_notification_type_id', 'user_notification_setting_id', 'slack_user_id', 'joinpoints_user_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function registered_events()
{
return $this->belongsToMany(Event::class, 'event_user', 'event_id', 'user_id');
}
}
Event.php
<?php
namespace App;
use App\User;
use App\EventRoom;
use App\EventType;
use App\EventStatus;
use App\EventLocation;
use App\EventParticipant;
use App\EventParticipantItems;
use Illuminate\Database\Eloquent\Model;
use Cviebrock\EloquentSluggable\Sluggable;
class Event extends Model
{
use Sluggable;
protected $fillable = [
'event_type_id', 'user_id', 'status', 'customer', 'slug', 'datetime', 'duration','embed_chat','number_of_participants','heading', 'description_1', 'description_2', 'livestream_link', 'logo_link', 'event_password', 'participants_per_room', 'youtube_id', 'embed_code', 'session_link', 'hide_breakout', 'help_link', 'lang', 'layout', 'btn2_text', 'btn2_link', 'help_text', 'background_url', 'black_font',
];
protected $dates = ['datetime'];
public function getRouteKeyName()
{
return 'slug';
}
/**
* Return the sluggable configuration array for this model.
*
* #return array
*/
public function sluggable()
{
return [
'slug' => [
'source' => 'customer'
]
];
}
public function registered_users()
{
return $this->belongsToMany(User::class, 'event_user', 'user_id', 'event_id')->withPivot('id', 'user_status', 'eventmanager', 'created_at', 'updated_at');
}
}
My Tables:
user: id,....
event: id,...
event_user: id, user_id, event_id,...

Look a bit closer at your models :
return $this->belongsToMany(Event::class, 'event_user', 'event_id', 'user_id');
and
return $this->belongsToMany(User::class, 'event_user', 'event_id', 'user_id');
Whilst the table is right, you will need to swap the order of event_id and user_id on one of them...

Looks like you swapped the (foreign) keys:
In User.php:
public function registered_events()
{
return $this->belongsToMany(Event::class, 'event_user', 'user_id', 'event_id');
}
In Event.php:
public function registered_users()
{
return $this->belongsToMany(User::class, 'event_user', 'event_id', 'user_id')->withPivot('id', 'user_status', 'eventmanager', 'created_at', 'updated_at');
}
As you follow the correct Laravel database structure, you could simply put
return $this->belongsToMany(Event::class); in User.php and
return $this->belongsToMany(User::class)->withPivot(...); in Event.php

Related

Attempt to read property "name" on null (View: C:\xampp\htdocs\Moja_OTT\resources\views\premium\profile.blade.php)

I want a simple program that shows the user profile after login. I used session and middleware. But it is saying that the name property is null. Please help me solve this error. I have used User model. The value of the properties are not retrieving from the database.
Blade code:
<h1>Profile</h1>
<h2>Welcome Mr/Ms {{$user->name}}</h2>
Logout
Model:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Models\PremiumModel;
class User extends Authenticatable implements MustVerifyEmail
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $table = 'users';
protected $primaryKey = 'user_id';
protected $timestamp = false;
protected $fillable = [
'name',
'email',
'password',
'type',
'email_verified_at',
'pro_pic',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
function admin()
{
return $this->hasOne('App\Models\admin', 'user_id', 'admin_id');
}
function premium()
{
return $this->hasMany(PremiumModel::class, 'user_id', 'user_id');
}
}
Controller code:
function profile()
{
$user = User::where('user_id',session()->get('logged'))->first();
return view('premium.profile')->with('user',$user);
}
Here, logged is the middleware.
You can try hasOne in the User model:
public function premium()
{
return $this->hasOne(PremiumModel::class, 'user_id', 'user_id');
}
Because hasMany returned an array, but hasOne returned just a single Object

Laravel 8 : How to create a Pivot Model with its associated migration?

I would like to create a model: FormsUser and the migration: forms_user
To use the table as a pivot because I have problems when I create a forms I am told that the table: 'forms_users does not exist' because I created the migration separately and
when I go to my group members management page I get the error: 'forms_users does not exist' because here I have to use a pivot table so it must have this table name...
Can you help me to solve this problem or suggest an alternative?
in short I want to create a forms and I create a team where I can add other user to the same forms.
migration: forms && Models Forms :
class Forms extends Model
{
use HasFactory;
use SoftDeletes;
protected $fillable = [
'title',
'description',
'date',
'color',
'progress',
'user_id',
'groupe_id',
'formulaire',
'logo',
];
protected $dates = [
'created_at',
'deleted_at',
'started_at',
'update_at'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function usersGroupe()
{
return $this->belongsToMany(User::class);
}
}
migration: users && Models User:
class User extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
use SoftDeletes;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'lastname',
'firstname',
'email',
'password',
'current_team_id',
'profile_photo_path',
'role_id',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
'profile_photo_url',
'role_id',
];
protected $dates = [
'created_at',
'deleted_at',
'started_at',
'update_at'
];
public function forms()
{
return $this->hasMany(Forms::class);
}
public function formGroupe()
{
return $this->belongsToMany(Forms::class);
}
public function role()
{
//return $this->hasMany(Role::class, 'id', 'role_id');
return $this->hasOne(Role::class, 'id', 'role_id');
}
public function user()
{
return $this->hasOne(User::class);
}
}
migration: formuser && Models FormsUser :
class FormsUser extends Model
{
use HasFactory;
protected $fillable = [
'forms_id',
'user_id'
];
}
migration create_forms_user :
Schema::create('forms_user', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->unsignedBigInteger('forms_id');
$table->foreign('forms_id')->references('id')->on('forms');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
So traditionally you don't have to create a pivot model. Laravel has some naming conventions that if you stick to will make things a bit easier. For example, Models should be singular but table names should be plural except for the pivot table. For example, your models should look like so:
class User extends Model { ... }
class Form extends Model { ... }
Then your table names would be :
users
forms
form_user
The pivot table should include the singular name of each table in alphabetical order. So F comes before U in the alphabet so it should read form_user.
Lastly in your Form model you would include a 'belongsToMany' function:
public function users() {
return $this->belongsToMany('App\User');
}
and in the User Model you would include the same in reverse:
public function forms() {
return $this->belongsToMany('App\Form');
}
If you entered the migrations correctly you will never need to create a pivot model. You can simply call the other objects through the relation to retrieve an array. ie:
$user->forms
$form->users
After a lot of hard work I was finally able to solve the problem so instead of storing the data via the Models pivot I did it directly via a request to the migration.
Anyway, thanks for your participation.
Problem solved!

Call to a member function hasVerifiedEmail() on null

I am using Laravel 7 and I am trying to verify my email I have followed all the steps mentioned in the documentation but I am still getting this error please me to resolve this error, Thanks
I added the user model code here
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name', 'last_name', 'email', 'password', 'permissions'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
here is web.php
Auth::routes(['verify'=> true]);
Route::prefix('student')->middleware(['auth', 'verified'])->group(function () {
Route::get('dashboard', 'StudentController#dashboard');
});
The $request is sending a null value because you need to be logged in (authenticated) in order to get an instance of the $user
Make sure you have a middleware of auth on your route
Assigning Middleware To Routes:
Route::get('admin/profile', function () {
//
})->middleware('auth');
or Middleware Groups:
Route::group(['middleware' => ['auth']], function () {
Route::get('admin/profile', function(){
//your function here
});
});
Laravel Official Doc
only users logged could acheave the function hasVerifiedEmail() , because of that you get the response : Call to a member function hasVerifiedEmail() on null ,
to fix that issue you have to customise show function in VerificationController.php
public function show(Request $request)
{
//login user
if (auth()->user())
{
return $request->user()->hasVerifiedEmail()
? redirect($this->redirectPath())
: view('auth.verify');
}
//guest
else
{
return $request->user()
? redirect($this->redirectPath())
: redirect('/login');
}
}

Lazy eager loaded relationship missing in toArray()

Laravel 5.8
I am lazy loading an user with the related customer which has a one-to-one-relation with a crmaccount-object
The models are working so that when i retrieve the eager-loaded entity it shows all of the nested relationships.
One row later i use the "toArray()" method on that object and the output is missing the third-level-relations.
The only thing which maybe some kind of special regarding the "crmaccount"-model is that it holds a column which is json an has to be casted.
Any idea what is going on here?
All of these happens in a middleware. No difference if i use with or load.
public function handle($request, Closure $next)
{
$UserData = \Auth::user();
if($UserData){
$User = \App\Login::with(['role','customer','customer.crmaccount'])->find($UserData->id);
dump($User);
dd($User->toArray());
$UserData['isAdmin'] = false;
if($UserData['role']['name'] === 'Admin'){
$UserData['isAdmin'] = true;
}
$request->request->add(['UserData' => $UserData]);
}
return $next($request);
}
Login
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Login extends Authenticatable{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password','customer_id','role_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/* */
public function Role(){
return $this->belongsTo('App\Role');
}
public function Customer(){
return $this->belongsTo('App\Customer');
}
/**
* [hasOpportunities Ruft alle Opportunities des Users ab. Da diese lediglich zwei Entitäten weiter sind, kann anstatt von dot-notated Lazy-Load auch die hasManyThrough-ORM-Methode genutzt werden]
* #return [hasManyThrough-Relation] [Die hasManyThrough-ORM-Beziehung]
*/
public function hasOpportunities(){
return $this->hasManyThrough(
'App\Opportunity',
'App\Customer',
'id',
'customer_id',
'customer_id'
);
}
/**
* [hasSalesreps Ruft alle SalesReps des Users ab. Da diese lediglich zwei Entitäten weiter sind, kann anstatt von dot-notated Lazy-Load auch die hasManyThrough-ORM-Methode genutzt werden]
* #return [hasManyThrough-Relation] [Die hasManyThrough-ORM-Beziehung]
*/
public function hasSalesreps(){
return $this->hasManyThrough(
'App\Salesrep',
'App\Customer',
'id',
'customer_id',
'customer_id'
);
}
}
Customer
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model{
public $timestamps = false;
protected $visible = ['id','name'];
protected $fillable = ['name'];
public function crmaccount(){
return $this->hasOne('App\Crmaccount');
}
public function Salesreps()
{
return $this->hasMany('App\Salesrep');
}
public function Prospects()
{
return $this->hasMany('App\Prospect');
}
public function Trees()
{
return $this->hasMany('App\Salesreptrees');
}
public function Opportunities()
{
return $this->hasMany('App\Opportunity');
}
public function User()
{
return $this->hasMany('App\Login');
}
}
Crmaccount
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Crmaccount extends Model{
public $timestamps = false;
protected $visible = ['id','name','crm_system','customer_id','crm_api_config'];
protected $fillable = [
'name','crm_system','customer_id','crm_api_config'
];
protected $casts = [
'crm_api_config' => 'array'
];
public function customer(){
return $this->belongsTo('App\Customer');
}
}
On every model, there is a protected $visible = []; and protected $hidden = [] attribute. These control the attributes that are available when the model is converted to an object, array or json. This includes relationships, as Laravel internally converts them to attributes, so omitting them from visible, or including them in hidden will cause them to not be available.
In Customer.php:
protected $visible = ['id','name'];
Since crmaccount is not in that array, only id and name will be available. Simply add crmaccount to the array to handle:
protected $visible = ['id','name', 'crmaccount'];
Alternatively, use hidden to explicitly set the attributes you don't want to show, and relationship, if loaded via ->with() will show by default.

eloquent one-To-Many-To-Many

Hi everyone I start with Laravel and eloquent and already I have a problem.
I have users, each user can have multiple vehicles and a vehicle can have multiple rentals. I want to list all rentals of each vehicle belonging to the current user.
User model:
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function vehicule()
{
return $this->hasMany('App\Models\Vehicule');
}
Vehicule model:
use Illuminate\Database\Eloquent\Model;
class Vehicule extends Model
{
protected $fillable = [
'user_id',
'published',
'rented'
];
public function user()
{
return $this->belongsTo('App\User');
}
public function rental()
{
return $this->hasMany('App\Models\Rental');
}
Rental model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Rental extends Model
{
protected $fillable = [
'from_date',
'to_date',
'amount_total',
'vehicule_id'
];
public function vehicule()
{
return $this->belongsTo('App\Models\Vehicule');
}
}
You can use your existing relationships:
$rentals = $user->load('vehicule.rental')->pluck('vehicule.rental')->collapse();
Or add a HasManyThrough relationship to User:
public function rental()
{
return $this->hasManyThrough(Rental::class, Vehicule::class);
}
$rentals = $user->rental;

Resources