How to push custom attribute to eloquent object (model) after fetch? - laravel

I have custom model User and I want push custom attribute to model after fetching data. How I can do it?
I know what before fetching we can add custom attibute like this:
class User extends Model
{
protected $appends = ['callable'];
public function getCallableAttribute()
{
$callable = $this->getMeta('phone') ? true : false;
return $callable;
}
}
But how do it after fetching data, for example after:
$user = User::find(1);
And now how append custom attribute to fetched User object data?

You can define a Laravel Accessor for that
E.g.
class User extends Model
{
/**
* Get the user's first name.
*
* #param string $value
* #return string
*/
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
/**
* Get the user's full name.
*
* #return string
*/
public function getFullNameAttribute()
{
return "{$this->first_name} {$this->last_name}";
}
}
Then you can access Accessors like this:
$user = App\User::find(1);
$firstName = $user->first_name; // In studly Case
$firstName = $user->full_name; // In studly Case
You can read more about Laravel Accessors here: https://laravel.com/docs/5.8/eloquent-mutators#defining-an-accessor

Related

How to get property or method in relationship ( laravel - eloquent )

in Post Model
function user()
{
return $this->belongsTo( \App\User::class);
}
in User Model
function posts()
{
return $this->hasMany( \App\Post::class);
}
function somedata()
{
return date('i') * 1000 + date('s');
}
in Controller
$posts = Post::query()
->where('id', 10)
->with('user')
->get();
but it does not get 'somedata' in user model .
How can I drag this data with posts ?
Try making it an attribute and append it in the model
Post.php
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = ['someData'];
/**
* Get the some data for the post.
*
* #return int
*/
public function getSomeDataAttribute()
{
return date('i') * 1000 + date('s');
}
You need to set an Accessor:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the user's somedata.
*
* #return string
*/
public function getSomedataAttribute()
{
return 'somedata';
}
}
Also see: https://laravel.com/docs/5.8/eloquent-mutators

define an alias name for primary key in a model that is extended in laravel

I have a Stuff Model like this :
class Stuff extends Model
{
protected $primaryKey = 'stuff_id';
protected $fillable = ['stuff_id' , 'title' , 'desc'];
protected $dates = ['deleted_at'];
}
In the other hand there is a Product model that extended from Stuff Model like this :
class Product extends Stuff
{
protected $fillable = ['quantity' , 'picture'];
}
As you can see beacause Product is extended from Stuff and primary key of Stuff is stuff_id , Anywhere that I want to call a Product instances and needs to print it's id should use a $product->stuff_id while I want use a clearer name for that like $product->product_id.
Is there any way that can define a alias primary key in child model that interpreted to stuff_id in back-end when running queries on database.
To turn product_id into an alias of stuff_id:
...
$product->product_id // resolves to $product->stuff_id
...
public function getProductIdAttribute(): int
{
return $this->stuff_id;
}
...
Instead of using $primaryKey, you can override the function that reads from that variable.
In your Stuff model, try adding something along the lines of:
/**
* Get the primary key for the model.
*
* #return string
*/
public function getKeyName(): string
{
return [
Stuff::class => 'stuff_id',
Product::class => 'product_id',
][get_class($this)];
}
And for reference, the default behavior: (Illuminate/Database/Eloquent/Model.php)
/**
* Get the primary key for the model.
*
* #return string
*/
public function getKeyName()
{
return $this->primaryKey;
}
Using Global Scope:
//Say ProductScope.php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Schema;
class ProductScope implements Scope
{
protected $model_name;
public function __construct($model_name)
{
$this->model_name = $model_name;
}
/**
* Apply the scope to a given Eloquent query builder.
*
* #param \Illuminate\Database\Eloquent\Builder $builder
* #param \Illuminate\Database\Eloquent\Model $model
* #return void
*/
public function apply(Builder $builder, Model $model)
{
$attr = Schema::getColumnListing($this->model_name);
$attr_ = array_map(function ($item){
return $item === 'stuff_id' ? $item.' as product_id' : $item;
}, $attr);
$builder->select($attr_);
}
}
Then in the Product Model:
use App\Scopes\ProductScope;
class Product extends Stuff
{
protected $table = 'stuffs';
protected $primaryKey = 'stuff_id';
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ProductScope('stuffs'));
}
}
This will replace the stuff_id with product_id

Laravel - Query scopes across models

In a nutshell, I want to create a function that my query scopes can use across multiple models:
public function scopeNormaliseCurrency($query,$targetCurrency) {
return $query->normaliseCurrencyFields(
['cost_per_day','cost_per_week'],
$targetCurrency
);
}
I have got my logic working within this scope function no problem, but I want to make this code available to all my models, as there are multiple currency fields in different tables and I don't want to be replicating the code in each query scope - only specify the columns that need attention.
So, where would I make my function normaliseCurrencyFields? I have extended the Model class as well as used the newCollection keyword to extend Collection but both result in Call to undefined method Illuminate\Database\Query\Builder::normaliseCurrencyFields() errors.
I have looked into Global Scoping but this seems to be localised to a Model.
Am I along the right lines? Should I be targeting Eloquent specifically?
Create an abstract base model that extends eloquent then extend it with the classes you want to have access to it. I do this for searching functions, uuid creation, and class code functions. So that all of my saved models are required to have to certain attributes and access to my searching functions. For instance I created a static search function getobjectbyid(). So that when extended I can call it like so:
$user = User::getobjectbyid('habwiifnbrklsnbbd1938');
Thus way I know I am getting a user object back.
My base model:
<?php
/**
* Created by PhpStorm.
* User: amac
* Date: 6/5/17
* Time: 12:45 AM
*/
namespace App;
use Illuminate\Database\Eloquent\Model as Eloquent;
abstract class Model extends Eloquent
{
protected $guarded = [
'class_code',
'id'
];
public $primaryKey = 'id';
public $incrementing = false;
public function __construct($attributes = array()) {
parent::__construct($attributes); // Eloquent
$this->class_code = \App\Enums\EnumClassCode::getValueByKey(get_class($this));
$this->id = $this->class_code . uniqid();
return $this;
}
public static function getObjectById($id){
$class = get_called_class();
$results = $class::find($id);
return $results;
}
public static function getAllObjects(){
$class = get_called_class();
return $class::all();
}
my user model:
<?php
namespace App;
use Mockery\Exception;
use Illuminate\Support\Facades\Hash;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use App\Model as Model;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use Authenticatable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'contact', 'username', 'email_address'
];
/**
* The column name of the "remember me" token.
*
* #var string
*/
protected $rememberTokenName = 'remember_token';
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'remember_token', 'active'
];
/**
* the attributes that should be guarded from Mass Assignment
*
* #var array
*/
protected $guarded = [
'created_at', 'updated_at', 'password_hash'
];
/**
* Define table to be used with this model. It defaults and assumes table names will have an s added to the end.
*for instance App\User table by default would be users
*/
protected $table = "user";
/**
* We have a non incrementing primary key
*
* #var bool
*/
public $incrementing = false;
/**
* relationships
*/
public function contact(){
// return $this->hasOne(Contact::class, 'id', 'contact_id');
return $this->hasOne(Contact::class);
}
public function customers(){
// return $this->hasOne(Contact::class, 'id', 'contact_id');
return $this->hasMany(Customer::class);
}
/**
* User constructor.
* #param array $attributes
*/
public function __construct($attributes = array()) {
parent::__construct($attributes); // Eloquent
// Your construct code.
$this->active = 1;
return $this;
}
/**
* #param $password string
* set user password_hash
* #return $this
*/
public function setPassword($password){
// TODO Password Validation
try{
$this->isActive();
$this->password_hash = Hash::make($password);
$this->save();
} catch(\Exception $e) {
dump($e->getMessage());
}
return $this;
}
/**
* Returns whether or not this use is active.
*
* #return bool
*/
public function isActive(){
if($this->active) {
return true;
} else {
Throw new Exception('This user is not active. Therefore you cannot change the password', 409);
}
}
public function getEmailUsername(){
$contact = Contact::getObjectById($this->contact_id);
$email = Email::getObjectById($contact->email_id);
return $email->username_prefix;
}
/**
* #return string
*
* getFullName
* returns concatenated first and last name of user.
*/
public function getFullName(){
return $this->first_name . ' ' . $this->last_name;
}
/**
* Get the name of the unique identifier for the user.
*
* #return string
*/
public function getAuthIdentifierName(){
return $this->getKeyName();
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier(){
return $this->{$this->getAuthIdentifierName()};
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword(){
return $this->password_hash;
}
/**
* Get the token value for the "remember me" session.
*
* #return string
*/
public function getRememberToken(){
if (! empty($this->getRememberTokenName())) {
return $this->{$this->getRememberTokenName()};
}
}
/**
* Set the token value for the "remember me" session.
*
* #param string $value
* #return void
*/
public function setRememberToken($value){
if (! empty($this->getRememberTokenName())) {
$this->{$this->getRememberTokenName()} = $value;
}
}
/**
* Get the column name for the "remember me" token.
*
* #return string
*/
public function getRememberTokenName(){
return $this->rememberTokenName;
}
/**
* Get the e-mail address where password reset links are sent.
*
* #return string
*/
public function getEmailForPasswordReset(){
}
/**
* Send the password reset notification.
*
* #param string $token
* #return void
*/
public function sendPasswordResetNotification($token){
}
public function validateAddress(){
}
}
a TestController:
public function test(){
$user = User::getObjectById('USR594079ca59746');
$customers = array();
foreach ($user->customers as $customer){
$contact = Contact::getObjectById($customer->contact_id);
$name = PersonName::getObjectById($contact->personname_id);
$c = new \stdClass();
$c->id = $customer->id;
$c->name = $name->preferred_name;
$customers[] = $c;
}
$response = response()->json($customers);
return $response;
}
Take note on how getObjectById is extended and available to my other classes that extend my base model. Also I do not have to specify in my user model an 'id' or 'class_code' and when my user model is constructed it calls the parent constructor which is the constructor on my base model that handles 'id' and 'class_code'.

How to set hidden attributes to an Controller method in Laravel5.0?

I want to hide some data which selected from database but reinitialize from some method in Controller not defined in its Models.
function ddd(){
return Client::select($this->_client)->with([
'Contact'=>function($s){
//$this->setHidden('use_id');
//$s->setHidden('use_id');
$s->select($this->_contact);
},
'Employer'=>function($s){$s->select($this->_employers);},
])->get();
}
You requirement is not very clear. However. I am assuming that you have 3 models Client hasOne Contact and belongsTo Employer.
In order to hide the use_id property of the Client model you can define a hidden property in your model
class Client extends Model
{
//will hide the `use_id` from the model's array and json representation.
protected $hidden = ['use_id'];
//Relations
/**
* Get the Contact which the given Client has.
* #return \Illuminate\Database\Eloquent\Relations\HasOne
* will return a App\Contact model
*/
public function contact()
{
return $this->hasOne('App\Contact');
}
/**
* Get the Employee to which the given Client belongs.
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
* will return a App\Employer model
*/
public function employer()
{
return $this->belongsTo('App\Employer');
}
}
Then in probably your ClientsController in some action ddd
public function ddd()
{
return Client::with('contact')->with('employer')->get();
}

Implemented a sidebar based on user with most posts and comments

i want to implement a sidebar based on user with most posts and comments in laravel 5.2 app,
i want to show the top 5 users with most posts and comment.
Exemple Like this:
User Name: "Mohcin", Post:30, answer:20
Thanks in advance
User model:
use Authenticatable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'email', 'password'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function questions(){
return $this->hasMany('\App\Question');
}
public function answers(){
return $this->hasMany('\App\Answer');
}
Question model: (posts model)
public function User(){
return $this->belongsTo('\App\User');
}
public function answers(){
return $this->hasMany('\App\Answer');
}
public static function your_questions(){
return static::where ('user_id','=',Auth::user()->id)->paginate(50);
}
public static function unsolved(){
return static::where ('solved','=',0)->orderby('id','DESC')->latest()->paginate(50);
}
public static function unsolvedbar(){
return static::where ('solved','=',0)->orderby('id','DESC')->latest()->take(3)->get();;
}
public function category()
{
return $this->belongsTo('App\Category');
}
public function tags()
{
return $this->belongsToMany('App\Tag');
}
Steps:
Open app/Providers/AppServiceProvider.php
In this file you have an empty (probably) boot method.
Inside this method, you can create a view composer to pass data for a specific view.
Like this:
//Assuming you want to pass the var to the view: sidebar.blade.php inside resources/views/layout
view()->composer('layout.sidebar', function($view){
$topUsers = User::topUsers(); //Create a query or scope to do this...
//After populate topUsers, you have to pass it to the view using:
$view->with('topUsers', $topUsers);
});
In your view: `resources/views/layout/sidebar.blade.php, you can access the users with a simple $topUsers like this:
foreach($topUsers as $user) {
var_dump($user);
}

Resources