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

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!

Related

Laravel Many-to-Many relationship not working

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

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;

Laravel many to many relation not working

I'm trying to fetch data from a relationship but only relationship properties are returned.
User Model
class User extends Authenticatable {
use SoftDeletes; use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [ 'name', 'email', ];
/*
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [ 'password', 'remember_token' ];
/*
* Get the images for the store.
*/
public function stores() {
return $this->belongsToMany('App\Store', 'store_user');
}
}
Stores Model
public function users() {
return $this->belongsToMany('App\User');
}
Pivot Table
public function up() {
Schema::dropIfExists('store_user');
Schema::create('store_user', function (Blueprint $table) {
$table->increments('id');
$table->integer('store_id');
$table->integer('user_id');
$table->timestamps();
});
}
Existing relations between pivot table and ids are accurate.
Retrieving relations
$user = Auth::user();
$userStores = $user->stores;
$storesID = [];
foreach ($userStores as $store) {
$storesID[] = $store->id;
}
$builder->whereIn('store_id', $storesID);
This returns:
Undefined property: App\User::$stores
I tried
$userStores = $user->stores()->get();
but that freezes the page until it throws a request took more than 60 seconds error.
Do you have any idea what I'm doing wrong?
The problem is 100% inside of your OwnerScope file, you should review that file first and then review the line where you assigned $builder it's value, I can't be of more help because you didn't include code from either so it's all we can do until you update your question and include both.
Looks like $user is not logged in, maybe check first with:
if (Auth::check()) {
}

How can I create DB table in Trait?

I have created a trait that creates a table in the database if it doesn't exist.
the table is created perfectly in the DB but I get an error. The error is throw by Illuminate\Database\Eloquent\Concerns\HasAttributes.php
TRAIT:
namespace App\Traits;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
trait Translatable{
//CREATE LANGUAGES TABLE IF DOES NOT EXIST
public function createTranslationTable()
{
//ADD LANGUAGES TABLE IF DOES NOT EXIST
if(Schema::hasTable('languages') === false){
Schema::create('languages', function (Blueprint $table) {
$table->increments('id');
$table->string('language');
$table->string('slug');
});
}
//CREATE TRANSLATION TABLE IF DOES NOT EXIST
if(Schema::hasTable('translations') === false){
Schema::create('translations', function (Blueprint $table) {
$table->increments('id');
$table->string('model');
$table->string('language_id');
$table->foreign('language_id')->references('id')->on('languages')->onDelete('cascade');
$table->string('field_name');
$table->string('field_translation');
});
}
}
public function translateMe()
{
$this->createTranslationTable;
}
}
ERROR:
App\User::createTranslationTable must return a relationship instance.
I am using a trait because I want it to be able to use it with any model like so for eaxample:
class User extends Authenticatable
{
use Notifiable;
use Translatable;
/**
* Call Translatable.
*
* #return void
*/
public function __construct()
{
$this->translateMe();
}
/**
* 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',
];
/**
* The attributes that are translatable.
*
* #var array
*/
protected $translatableItems = [
'name'
];
}
I found the solution and it was one simple one.
In the Translatable trait I was calling createTranslationTable method as a property instead then a method. so just adding the two parentesis fixed it.
BEFORE:
public function translateMe()
{
$this->createTranslationTable;
}
NOW:
public function translateMe()
{
$this->createTranslationTable();
}

Do something before saving model to database in Laravel 5.1

How can I do something such as modify some data fields or more validate before writing data to database in Laravel 5.1 model ?
It's document about that problem is hard to use in real application: http://laravel.com/docs/5.1/eloquent#events
My code is
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Helpers\Tools as Tools;
class Atoken extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'atoken';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'token',
'user_id',
'role',
];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = [
];
public static function newToken($userId, $role){
# Remove all token assoiciate with input user;
Atoken::where('user_id', $userId)->delete();
$params = [
'user_id' => $userId,
'role' => $role,
];
Atoken::insert($params);
$item = Atoken::where('user_id', $userId)->first();
return $item->token;
}
protected static function boot(){
static::creating(function ($model) {
$model->token = 'sometoken';
});
}
}
In this case, I always got error:
SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"token\" violates not-null constraint (SQL: insert into \"atoken\" (\"user_id\", \"role\") values (2, USER))
How can I fix it?
class Lunch extends Eloquent
{
protected static function boot()
{
static::creating(function ($model) {
$model->topping = 'Butter';
return $model->validate();
});
}
protected function validate()
{
// Obviously do real validation here :)
return rand(0, 1) ? true : false;
}
public static function newToken($userId, $role)
{
static::where('user_id', $userId)->delete();
return static::create([
'user_id' => $userId,
'role' => $role,
])->token;
}
}
I would recommend to go into EventServiceProvider, and register event listeners
public function boot(DispatcherContract $events)
{
parent::boot($events);
// Register Event Listeners
\App\Product::updating(function ($product) {
$product->onUpdating();
});
...
then create function onUpdating within the model. You also can choose from saving, saved, creating, created, updating, updated..
This documentation has more:
https://laravel.com/docs/5.1/eloquent#events

Resources