Laravel many to many relation not working - laravel

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()) {
}

Related

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!

Laravel: How do i fix this trait (with attributes) to also work when creating a model?

I'm using a trait to dynamically add e-mail attribute(s) to a model. It gives me the possibility to reuse code amongst many models. However, this code fails when i try to create a new model (but succeeds when i update an existing model).
The issue is the assumption that $this->id is available in Traits/Contact/HasEmails > setEmailTypeAttribute. Id is not yet available, because saving is not finished.
My question: How can i fix this trait to also work when creating a model?
Google, no results
Thinking about something of model events (static::creating($model))
\app\Traits\Contact\HasEmails.php
/*
* EmailGeneric getter. Called when $model->EmailGeneric is requested.
*/
public function getEmailGenericAttribute() :?string
{
return $this->getEmailTypeAttribute(EmailType::GENERIC);
}
/*
* EmailGeneric setter. Called when $model->EmailGeneric is set.
*/
public function setEmailGenericAttribute($email)
{
return $this->setEmailTypeAttribute(EmailType::GENERIC, $email);
}
/*
* Get single e-mail model for model owner
*/
private function getEmailTypeAttribute($emailType) :?string
{
$emailModel = $this->emailModelForType($emailType);
return $emailModel ? $emailModel->email : null;
}
/*
* Update or create single e-mail model for model owner
*
* #return void
*/
private function setEmailTypeAttribute($emailType, $email) :void
{
$this->emails()->updateOrCreate([
'owned_by_type' => static::class,
'owned_by_id' => $this->id,
'type' => $emailType
],['email' => $email]);
}
\app\Models\Email.php
namespace App\Models;
class Email extends Model
{
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'email'
];
/*
* Get polymorphic owner
*/
public function ownedBy(): \Illuminate\Database\Eloquent\Relations\MorphTo
{
return $this->morphTo();
}
/*
* Default attributes are prefilled
*/
protected function addDefaultAttributes(): void
{
$attributes = [];
$attributes['type'] = \App\Enums\EmailType::GENERIC;
$this->attributes = array_merge($this->attributes, $attributes);
}
}
\migrations\2019_10_16_101845_create_emails_table.php
Schema::create('emails', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('owned_by_id');
$table->string('owned_by_type');
$table->string('type'); //f.e. assumes EmailType
$table->string('email');
$table->unique(['owned_by_id', 'owned_by_type', 'type'], 'owner_type_unique');
});
I expect a related model to be created/updated, but it fails on creating.
Trick was using a saved model event and also not forgetting to set the fillable attribute on the email model:
/*
* Update or create single e-mail model for model owner
*
* #return void
*/
private function setEmailTypeAttribute($emailType, $email) :void
{
static::saved(static function($model) use($emailType, $email) {
$model->emails()
->updateOrCreate(
[
'owned_by_type' => get_class($model),
'owned_by_id' => $model->id,
'type' => $emailType
],
[
'email' => $email
]);
});
}

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

Delete on Eloquent doesn't delete Laravel 5.4

I am trying to make a delete functionality for pictures which users can upload. The model of the picture class:
class Picture extends Model
{
use SoftDeletes;
/**
* The attributes that are mass assignable.
* #var array
*/
protected $fillable = ['original_file', 'resized_file'];
/**
* The attributes that should be mutated to dates.
* #var array
*/
protected $dates = ['deleted_at'];
/**
* Get the category that owns the question.
*/
public function user()
{
return $this->belongsTo(User::class);
}
Migration:
$table->timestamps();
$table->softDeletes();
The delete function which I have:
public function destroyProgress(Picture $progress){
$progress->delete();
dd($progress);
return view('client.home.profile', ['user' => Auth::user()]);
}
This code is executed and stoped at the dd($progress);. I would expect that this would return null because the $progress has been deleted. But this still returns an instance! Could someone please explain to me what I am doing wrong because I am lost for words.
Hard to explain, the object $progress created by dependency injection is not actually a model instance. Therefore, the delete event will not be fired.
You should use delete method on a model instance:
$picture = App\Picture::find(1);
$picture->delete();

Laravel Relationship Issues : Laravel 5.4

I have 2 tables in my application... Users Conventioners
I have users id in the conventioners table and i want to access their genders from the Users table....
I have like 10 user ids in the conventioners table and 20 users in the users table...
Please how do I access all their genders in the users table...
$conventioners->users()->gender
Conventioners is an instance of the Conventioner Model which contains a relationship **belongsToMany
Thanks alot guys
Here is my Conventioner Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Conventioner extends Model
{
/**
* #var string
*/
protected $table = 'conventioners';
/**
* #var array
*/
protected $fillable = [
'user_id','year','church_id','convention_id'
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('App\User');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function users()
{
return $this->hasMany('App\User');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function convention()
{
return $this->belongsTo('App\Convention');
}
}
Here is my ConventionController method called Convention...
It retrieves the details for the current convention
public function convention($slug)
{
if(!$this->admin()) return redirect()->back();
$convention = Convention::where('slug', $slug)->first();
$participants = Conventioner::where('convention_id', $convention->id)->get();
$conventioner = [];
foreach($participants as $participant)
{
$thisUser = [];
$thisUser['data'] = User::withTrashed()->where('id', $participant->user_id)->first();
$thisUser['convention'] = $participant;
array_push($conventioner, $thisUser);
}
var_dump($participants->users()->pluck('gender')->all());
return view('dashboard/conventions/convention', [
'convention' => $convention,
'user' => Auth::user(),
'conventioners' => $convention->conventioners(),
'participants' => $conventioner
]);
}
The problem is that users is a collection not an individual that you can call gender on. If you want a list of all the genders you can use the following:
Conventioner::where('convention_id', $convention->id)->with('users')->get()
$conventioners->pluck('users')->pluck('gender')->all();
This will return an array of the genders. You can read more about pluck here.
The pluck method retrieves all of the values for a given key

Resources