I'm trying to create a link in between 2 objects using NeoEloquent. Unfortunately i get the following error.
Class 'Permission' not found
I tried pretty much everything but i can't get it to work unfortunately.
I submit the permission objects I want to link to as an integer representing the id of the label.
The relationship between the labels is a Many to Many relation. As far as i can see i've done everything correctly. I've checked with the GitHub page, it looks good to me.
Thanks in advance!
Controller method:
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param Role $role
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Role $role)
{
//dd($request);
$this->validate($request, [
'title' => 'required',
]);
foreach($request['permission'] as $perm){
$role->permissions()->attach($perm);
}
$role->title = request('title');
$role->save();
return redirect("/roles");
}
Role Model:
<?php
namespace App;
use Vinelab\NeoEloquent\Eloquent\Model as NeoEloquent;
class Role extends NeoEloquent
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title',
];
protected $label = "Role";
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
public function permissions(){
return $this->hasMany('Permission', 'Has_Permission');
}
}
Permission Model:
<?php
namespace App;
use Vinelab\NeoEloquent\Eloquent\Model as NeoEloquent;
class Permission extends NeoEloquent
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title',
];
protected $label = "Permission";
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
}
Related
I need to check the email of my users. So I add a new attribute to my User model named "is_verified" that returns me a boolean to know if the user has checked the email or not.
I running on PHP 7.2.5 with PHPUnit 7.5.15 and Laravel 5.8
model: User.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Str;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'email', 'password', 'token', 'email_verified_at'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Retrive if user as vierfied
*
* #return boolean
*/
public function getIsVerifiedAttribute()
{
// dump(!is_null($this->email_verfied_at));
return !is_null($this->email_verfied_at);
}
/**
* Set if user is verified
*
* #param boolean $status
* #return void
*/
public function setIsVerifiedAttribute(bool $value)
{
if ($value) {
$this->attributes['token'] = null;
$this->attributes['email_verified_at'] = now();
} else {
$this->attributes['token'] = self::generateToken();
$this->attributes['email_verified_at'] = null;
}
}
/**
* Generate token to verify email
*
* #param integer $length
* #return string
*/
public static function generateToken(int $length = 64): string
{
$token = Str::random($length);
if (self::where('token', $token)->exists())
{
return self::generateToken($length);
}
return $token;
}
}
My unit test:
/** #test */
public function check_if_user_as_validate_email()
{
$user = factory(User::class)->create();
$this->assertFalse($user->is_verified);
$user->is_verified = true;
$user->save();
$this->assertTrue($user->is_verified);
$user->is_verified = false;
$user->save();
$this->assertFalse($user->is_verified);
}
The functions do not return me the good value every time
The reason your test isn't working is because you have a typo in your getIsVerifiedAttribute accessor. email_verfied_at should be email_verified_at.
public function getIsVerifiedAttribute()
{
return !is_null($this->email_verified_at);
}
Out-of-the-box, the User factory sets the email_verified_at field for you so I would suggest you change the code in your test for creating a User to:
$user = factory(User::class)->create([
'email_verified_at' => null
]);
This next bit is just an FYI but there are already methods included in with Laravel to check if a User is verified or not and to set the email_verified_at value:
$user->hasVerifiedEmail();
and
$user->markEmailAsVerified();
My Code Here is Working Fine but although he is returning user Role in the return can i prevent user roles from returning it's belongs to relation using role_id in users Table
$paths = Path::with(['user','tags'])->where('category_id',1)->get();
foreach($paths as $path){
if($path->user->hasRole('admin')){
$AdminPaths [] = $path;
}
if($path->user->hasRole('user')){
$UserPaths [] = $path;
}
}
return $UserPaths;
My User Model
class User extends \TCG\Voyager\Models\User
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password', 'username'
];
/**
* 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',
];
}
You are calling the function hasRole from here:
https://github.com/the-control-group/voyager/blob/1.2/src/Traits/VoyagerUser.php
It executes loadRolesRelations() that loads the roles relationships and thats why users come with the role relation loaded.
You could just unset the role relation after checking the role like:
foreach($paths as $path){
if($path->user->hasRole('admin')){
$AdminPaths [] = $path;
}
if($path->user->hasRole('user')){
$UserPaths [] = $path;
}
unset($path->user->role);
}
I'm experiencing my first Laravel project and I implemented a resource collection API, where I fetch data via passport. Data seems to be retrieved correctly from model, except for relations. Here's the situation:
item.php (Model)
<?php
// Definizione Namespace
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Classe Item
*/
class Item extends Model
{
use SoftDeletes;
// Dichiarazione Proprietà
protected $table = 'item';
protected $dateformat = 'Y-m-d';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'data_acquisto',
'labeled',
'estensione_garanzia',
'stato',
'data_dismissione',
'note'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'codice',
'serial',
'componente_id',
'tipologia_id',
'condizione_id',
'locazione_id',
'fornitore_id',
'parent_id'
];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [
'data_acquisto',
'data_dismissione',
'deleted_at'
];
/**
* All of the relationships to be touched.
*
* #var array
*/
protected $touches = [
'componenti',
'condizioni',
'fornitori',
'locazioni',
'tipologie'
];
/**
* Scope query item figli
* Getter
* #param array $query Query
* #return array Query
*/
public function scopeFigli($query)
{
return $query->where('parent_id', '!=', null);
}
/**
* Componenti Correlati
* Getter
* #return object Componenti
*/
public function componenti()
{
// Definizione relazione
return $this->belongsTo('App\Componente');
}
/**
* Condizioni Correlate
* Getter
* #return object Condizioni
*/
public function condizioni()
{
// Definizione relazione
return $this->belongsTo('App\Condizione');
}
/**
* Fornitori Correlati
* Getter
* #return object Fornitori
*/
public function fornitori()
{
// Definizione relazione
return $this->belongsTo('App\Fornitore');
}
/**
* Locazioni Correlate
* Getter
* #return object Locazioni
*/
public function locazioni()
{
// Definizione relazione
return $this->belongsTo('App\Locazione');
}
/**
* Tipologie Correlate
* Getter
* #return object Tipologie
*/
public function tipologie()
{
// Definizione relazione
return $this->belongsTo('App\Tipologia');
}
}
item.php (Resource)
<?php
// Definizione Namespace
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\Componente as ComponenteResource;
use App\Http\Resources\Condizione as CondizioneResource;
use App\Http\Resources\Fornitore as FornitoreResource;
use App\Http\Resources\Locazione as LocazioneResource;
use App\Http\Resources\Tipologia as TipologiaResource;
class Item extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
parent::toArray($request);
return [
'id' => $this->id,
'codice' => $this->codice,
'data_acquisto' => $this->data_acqisto,
'serial' => $this->serial,
'labeled' => $this->labeled,
'estensione_garanzia' => $this->estensione_garanzia,
'stato' => $this->stato,
'data_dismissione' => $this->data_dismissione,
'note' => $this->note,
'parent_id' => $this->parent_id,
// Includi associazioni se caricate
'componenti' => ComponenteResource::collection($this->whenLoaded('componenti')),
'condizioni' => CondizioneResource::collection($this->whenLoaded('condizioni')),
'fornitori' => FornitoreResource::collection($this->whenLoaded('fornitori')),
'locazioni' => LocazioneResource::collection($this->whenLoaded('locazioni')),
'tipologie' => TipologiaResource::collection($this->whenLoaded('tipologie'))
];
}
}
This is the screen about an example of data fetched:
As showed above there's no trace of relations. By googling around and changing code as suggested like this:
// Resoruce - Straight including relations instead of lazy load
[...]
'componenti' => ComponenteResource::collection($this->componenti),
[...]
or by expliciting the foreign key in model:
/**
* Componenti Correlati
* Getter
* #return object Componenti
*/
public function componenti()
{
// Definizione relazione
return $this->belongsTo('App\Componente', 'componente_id');
}
I'm still not retrieving relations.
Could anyone give me a little help/tip to solve this problem?
Thanks in advance for help.
The code below will only show Tipologie when it is explicitly loaded to avoid N+1 query problems.
'tipologie' => TipologiaResource::collection($this->whenLoaded('tipologia'))
To load Tipologie for Resource to show it, you need to explicitly load it as:
$itemResource = new ItemResource($item->load('tipologia', ... other relationships...);
See Eager Loading for more information about this.
Edit
Sorry for not understanding the type of relationship, just like #luca-cattide said, collection should not be used for belongsTo, and the correct one is to use:
TipologiaResource::make($this->tipologia);
Or also:
new TipologiaResource($this->topologia);
But I advise you to use "load" method to load the information before, otherwise you perform a search in the database for "item", another by "typologie" and so on until loading all your relationships.
There's another way you load information without having to load the item, see below:
new ItemResource(App\Item::find(1)->with(['tipologie', ... other relationships ... ])->get());
See more about N+1 query problems here.
Thanks #vinicius, but googling around a bit more, as suggested from this post by #CamiloManrique, I noticed that in these relations, I'm trying to fetch data from belongs_to side (so actually from Item and not from Componente, Tipologia and so on). As is ::collection simply doesn't work except if called by hasMany relation side
So, instead using ::collection in conjunction with whenLoaded I refactored like this:
// Includi associazioni se caricate
'componente' => ComponenteResource::make($this->componente),
'condizione' => CondizioneResource::make($this->condizione),
'fornitore' => FornitoreResource::make($this->fornitore),
'locazione' => LocazioneResource::make($this->locazione),
'tipologia' => TipologiaResource::make($this->tipologia)
In this way data being fetched with no error.
Thanks again for your tips.
I have a php laravel projekt where I need to add a field to one/more models (Eloquent). I don't have much experience in php and never tried laravel before.
The class looks like this now
class Player extends Eloquent
{
use GenderTrait;
use VisibilityTrait;
use PlayerPhotoTrait;
use PlayerActionTrait;
const GENDER_MALE = 2;
const GENDER_FEMALE = 1;
/**
* The database table used by model.
*
* #var string
*/
protected $table = 'players';
/**
* Parameters for `actions` relation.
*
* #see PlayerActionTrait::actions()
* #var array
*/
protected $actionModel = [
'name' => 'PlayerAction',
'foreignKey' => 'player_id',
];
/**
* The list of mass-assignable attributes.
*
* #var array
*/
protected $fillable = [
'name',
'start_value',
'gender',
'is_visible',
'nation',
];
/**
* The list of validation rules.
*
* #var array
*/
public static $rules = [
'name' => 'required',
'nation' => 'required|numeric',
'start_value' => 'required|numeric',
];
/**
* #inheritdoc
*/
protected static function boot()
{
parent::boot();
}
/**
* Players country.
*
* #return Country
*/
public function country()
{
return $this->belongsTo('Country', 'nation');
}
/**
* Player videos.
*
* #return mixed
*/
public function videos()
{
return $this->morphMany('YoutubeLink', 'owner');
}
}
I would like to add a string field called "level" but I have no idea how to go about it. If I create the field in MySQL first and then the models get updated, if I update the models and then Laravel update MySQL for me?
Im looking forward to hearing what I can do :)
You need to add migration:
php artisan make:migration add_fields_to_players_table --table=players
Open in /database/migrations new migration and write
Schema::table('players', function ($table) {
$table->string('new_string_field');
});
Now you need to run migrations
php artisan migrate
More info and available column types here
Trying to get data from multiple nested relationship with a where constraint:
Model User:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
use Illuminate\Database\Eloquent\SoftDeletingTrait;
use Zizaco\Entrust\HasRole;
class User extends BaseModel implements UserInterface, RemindableInterface {
use HasRole;
protected $fillable = array('username', 'password');
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
protected $dates = ['deleted_at'];
protected $softDelete = true;
public function editor()
{
return $this->hasOne('User_Editor', 'user_id');
}
?>
Model User_Editor:
<?php
class User_Editor extends BaseModel {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users_editors';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array();
/**
* Defiens the column names of fillable columns.
*
* #var array
*/
protected $fillable = array();
/**
* Relationships
*/
public function credentials()
{
return $this->hasMany('User_Editor_Credential', 'user_editor_id');
}
public function specialties()
{
return $this->hasMany('User_Editor_Specialty', 'user_editor_id');
}
?>
Model User_Editor_Credentials:
<?php
class User_Editor_Credential extends BaseModel {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users_editors_credentials';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array();
/**
* Defiens the column names of fillable columns.
*
* #var array
*/
protected $fillable = array();
}
Model User_Editor_Specialties:
<?php
class User_Editor_Specialty extends BaseModel {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users_editors_specialties';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array();
/**
* Defiens the column names of fillable columns.
*
* #var array
*/
protected $fillable = array();
}
Return
select * from User, User_Editor, User_Editor_Credentials, User_Editor_Specialty where User_Editor_Specialty.specialty In (array).
So far I've tried,
$this->data['editors'] = User::with(['editor.credentials.specialties' => function($q) use($data){
$q->whereIn('specialty',$data);
}])
->get();
But this throws an error call to undefined method specialties. Please guide, thanks.
To those who might have suffered for long trying to find a way to work around nested relationships, and also, if you are writing a join condition with whereIn (which throws call to undefined method because of a bug in the Laravel), Please find below ans,
$editors = User::with(['editor.credentials','editor.specialties']);
$this->data['editors'] = $editors->whereHas('editor', function($q) use ($a_data){
$q->whereHas('specialties',function($sq) use($a_data){
$sq->whereIn('specialty',$a_data);
});
})->get();
Update: the PR has been just merged to 4.2, so now it's possible to use dot nested notation in has methods ( ->has('relation1.relation2) ->whereHas('relation1.relation2, .. )
Your dot notated relations must be logically chained:
`with(['editor.credentials', ' editor.specialties' => function ....
You tried to search for the specialties relation on the User_Editor_Credential model.
According to the comments:
User::with(['editor.credentials','editor.specialties'])
->whereHas('editor' => function($q) use ($data){
$q->whereHas('specialties' => function($q) use ($data){
$q->whereIn('specialty',$data);
});
})->get();
or if you use my PR https://github.com/laravel/framework/pull/4954
User::with(['editor.credentials','editor.specialties'])
->whereHas('editor.specialties' => function($q) use ($data){
$q->whereIn('specialty',$data);
})->get();
It will return all the users that have related editor.specialties matching whereIn, with related editor and all its related credentials and specialties (the latter won't be filtered)