PhpStorm 2022.2.2 Laravel Model Relationships and Attributes recognised as magic methods - laravel

How can I declare my model relationships and custom attributes properly so that they will be available from auto-completion and have the warning "property accessed via magic method" disappear?
I have nothing above my Model class and I've tried a few examples but none seems to work. i.e #method, #param or I just can't figure out the proper syntax for it.
quantity_remaining is a custom attribute for my Model.
I have it like this ATM:
class MyModel extends Model
{
/**
* #return HasOne
*/
public function packages(): HasOne{
return $this->hasOne(Package::class, 'related_id', 'related_id');
}
public function getQuantityRemainingAttribute(): Int{
//more codes here but not needed for this example
return 1;
}
}

You might want to define properties in the class doc block. I renamed the packages relationship to package, because it is a hasOne relationship.
/**
* #property Package $packages
* #property int quantity_remaining
*/
class MyModel extends Model
{
public function package(): HasOne{
return $this->hasOne(Package::class, 'related_id', 'related_id');
}
public function getQuantityRemainingAttribute(): Int{
return 1;
}
}

You will need to define fields in model class like:
public mixed $name;
public mixed $surname;
public mixed $email;
public mixed $password;
while your fillables are:
protected $fillables = ['name', 'surname', 'email', 'password'];

Related

Model event is not triggered on laravel

I have a class that inherits a base class and uses a trait ... I will put the code below ..
The base class is using basically to do a validation before the rescue, using for this the saving event in the boot.
The trait is to tell the class to use uuid in the id attribute .. this trait uses the creating event of the boot.
In the class itself, the boot saving event is used to check if an active record exists.
In this code the trait creating event is not being triggered ... I can not do a save because uuid is not generated ... if I take the boot method in the final class the creating event is executed ...
something I'm not seeing ... does anybody have any idea what may be happening?
MAIN CLASS
class AcademicYear extends BaseModel
{
use UseUuid;
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::saving(function($model)
{
if($model->attributes['disable'] == false){
$model->searchActiveRecord();
}
});
}
public function searchActiveRecord(){
if ($this::where('disable', false)->count() >= 1){
throw new \App\Exceptions\OperationNotAllowed('operation not allowed', 'there is an active record', '422');
}
return true;
}
}
BASE MODEL
class BaseModel extends Model
{
/**
* If the model will be validated in saving
*
* #var bool
*/
protected static $validate = true;
/**
* Rules that will be used to validate the model
*
* #var array
*/
protected $validationRules = [];
/**
* Create a new base model instance.
*
* #param array $attributes
* #return void
*/
public function __construct($attributes = [])
{
parent::__construct($attributes);
}
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::saving(function($model)
{
if ($model::$validate) {
$model->validate();
}
});
}
/**
* Execute validation of model attributes.
*
* #return void
*/
public function validate()
{
$validator = Validator::make($this->attributesToArray(), $this->validationRules);
if($validator->fails()) {
throw new \App\Exceptions\OperationNotAllowed('validation failed', $validator->messages(), '422');
}
return true;
}
}
TRAIT
trait UseUuid
{
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model)
{
$model->incrementing = false;
$model->keyType = 'string';
$model->{$model->getKeyName()} = Str::uuid()->toString();
});
static::retrieved(function ($model)
{
$model->incrementing = false;
});
}
}
Your model's boot method is conflicting with the trait's boot method, because they have the same name.
From the PHP.net manual on Traits:
An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.
Current class: AcademicYear
Trait: UseUuid
Inherited class: BaseModel
If you want to use a boot method on an individual model, you'll have to alias the trait's method to something different:
class AcademicYear extends BaseModel
{
use UseUuid {
boot as uuidBoot;
}
// ...
protected static function boot()
{
static::uuidBoot();
// Your model-specific boot code here.
}
}
Be careful with where you place parent::boot(). If you call parent::boot() in both your trait and your model, BaseModel::boot() will be called more than once.

How to Declare a Different Database Connection in laravel Controller

I have a Controller and I need to set the Database for my Query Builder,
all is working but when I create new function I need to redeclare a connection,
What I need is to declare the connection so that the whole controller will be connecting with that database.
class CompanyInformationController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function firstFunction()
{
$connection = DB::connection('fdis_1');
return $connection->getDatabaseName();
}
public function secondFunction()
{
// This is redundant
$connection = DB::connection('fdis_1');
return $connection->getDatabaseName();
}
}
in a class on controller
private $connection;
public function __construct()
{
$this->connection = DB::connection('fdis_1');
}
now use into your method like
$this->connection->getDatabaseName();

Eloquent model inheritance hierarchy

I have a case where 2 eloquent models should inherit properties from a User model, but the User itself should not exist as a standalone instance. (Mentors and Students, both inherit from User class). So what I'm currently doing is:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
abstract 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',
];
/**
* Get the courses that the user has enrolled into
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function courses()
{
return $this->hasMany('App\Models\Course', 'user_course', 'user_id', 'course_id');
}
}
class Student extends User
{
protected $table = 'students';
/**
* Get the mentors that the user has hired
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function mentors()
{
return $this->hasMany('App\Models\User');
}
}
class Mentor extends User
{
protected $table = 'mentors';
/**
* Get a list of courses that a mentor is teaching
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function ownCourses()
{
return $this->hasMany('App\Models\Course', 'mentor_course', 'mentor_id', 'course_id');
}
}
I am wondering whether this is the correct to do what I am trying to accomplish?
IMHO I will use polymorhic relation:
Use three tables: users, students and mentors; in the users table add two fields: userable_id (integer), userable_type (string).
User model
class class User extends Authenticatable
{
public function userable()
{
return $this->morphTo();
}
Student model:
class Student extends Model
{
public function user()
{
return $this->morphOne('App\User', 'userable');
}
Mentor model:
class Mentor extends Model
{
public function user()
{
return $this->morphOne('App\User', 'userable');
}
Now User::find($id)->userable return a Student or a Mentor object depending on the value of the userable_type
I leave the others relations to you, I hope this helps.

Add custom atrribute to json response

I have model something like that with custom attribute
class MyModel extends Model
{
public function getExtraAttribute(){
return 'some string'; //etc.
}
}
And for controller method i have this
return MyModel::where('user_id', Auth::user()->id)->get();
But i don't see 'extra' attribute on json response
P.s. extra isn't column from database.
Add the attribute to $appends.
class MyModel extends Model {
...
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = ['extra'];
...
}
As per the docs here: https://laravel.com/docs/5.4/eloquent-serialization#appending-values-to-json
class User extends Model
{
protected $appends = ['extra'];
public function getExtraAttribute()
{
return $this->attributes['extra'] = 'some string...';
}
}

Print user group name with Auth::User()->user_group->name in Laravel 4

I'm trying to display the user group name in a view using Auth::user()->user_group->name, but apparently that doesn't work as I keep getting Trying to get property of non-object.
The code goes as follow
User_Group.php Model
<?php
class User_Group extends Eloquent {
protected $table = 'user_groups';
public function users() {
return $this->hasMany('User');
}
}
User.php Model
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
/**
* 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', 'remember_token');
public function user_group()
{
return $this->belongsTo('User_Group', 'user_groups_id');
}
public function getGravatarAttribute()
{
$hash = md5(strtolower(trim($this->attributes['email'])));
return "http://www.gravatar.com/avatar/$hash?s=100";
}
public function isAdmin()
{
return $this->user_groups_id == 1;
}
}
My profile.blade.php view
<small><p class="pull-right">{{ Auth::user()->user_group->name }}</p></small>
Doing the following will print the user group id reference though:
{{ Auth::user()->user_groups_id }}
Rename the method to group instead of user_group

Resources