Attach relation data directly to model - laravel

Article model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Articles extends Model
{
protected $table = 'articles';
protected $primaryKey = 'idArticle';
protected $fillable = [
'idArticle', 'Topic', 'Image', 'Content', 'Views',
];
protected $hidden = [
'idCategory', 'idUser',
];
public function category()
{
return $this->hasOne(Categories::class, 'idCategory', 'idCategory');
}
}
So now when i call $article = Articles::find(1);, it will returns data from articles table, when i add $article->category;, it adds data $article->category->Name. I would like to have that Name directly inside $article - something like $article->category (so $article->category->Name into $article->category) is it possible to define that just using model class or i need to map it inside controller?

You can assign custom attributes to your Model classes. But you can't use the same property name as your category() method, because it's already accessed by $article->category.
An example giving you a property called category_name
class Articles extends Model
{
// attributes to append to JSON responses
protected $appends = ['category_name'];
// ... your other properties and methods
// your custom attribute
public function getCategoryNameAttribute()
{
if (!is_null($this->category)) {
return $this->category->Name;
}
return '';
}
}
Use as:
$article->category_name

You can use appends, as mentioned by #matticustard or just use the ->with() method while retrieving your model:
$article = Articles::find($id)->with('category');
Then, you can access the category name with:
$categoryName = $article->category->name;
Hope it helps.

Related

How to set a value using Mutators in a model?

I have a model where I am using a mutator for logged in user, assign id. But the value is not passed.
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
class Pass extends Model
{
use HasFactory;
protected $fillable = [
'title',
'user_id',
'source',
'category_id',
];
public function setUserIdAttribute()
{
$this->attributes['user_id'] = Auth::user()->id;
}
}
You should look at append Laravel documentation. Adding your attributes to the protected $appends array should add your attribute to your final model output.
So try:
protected $appends = ['user_id'];
Laravel has built-in methods to appends attributes to your model output. If for any reason, you cannot use those default methods, you can use setRawAttributes to dynamically add the field to your model. But laravel standard way should be better.
protected $attributes;
public function __construct(array $attributes = array())
{
$this->setRawAttributes(array(
'user_id' => Auth::user()->id), true);
parent::__construct($attributes);
}

hasMany relationships return Undefined property

I like to list all MovimentoProdutoUnidade that movimento_id = 3 using the hasMany function.
My Model Movimento:
use Illuminate\Database\Eloquent\Model;
use App\Unidade;
class Movimento extends Model
{
protected $fillable = [
"movimento", "descricao", "requisitante", "despachante", "data", "unidade_ori_id", "unidade_des_id"
];
protected $table = "movimentos";
public function movimentoProdutoUnidade(){
return $this->hasMany('App\MovimentoProdutoUnidade', 'movimento_id');
}
}
My Model MovimentoProdutoUnidade
use Illuminate\Database\Eloquent\Model;
use App\Movimento;
class MovimentoProdutoUnidade extends Model
{
protected $fillable = [
"movimento_id", "unidadeProduto_id"
];
protected $table = "movimento_produtounidades";
public function movimento(){
return $this->belongsTo('App\Movimento', 'movimento_id');
}
}
My Controller:
public function licitacao(Request $request){
$movimentos = Movimento::where('unidade_ori_id', 3)->movimentoProdutoUnidade;
dd($movimentos);
//return view('relatorios.licitacao', compact('movimentos'));
}
The dd fuction return
Undefined property: Illuminate\Database\Eloquent\Builder::$movimentoProdutoUnidade
Your error is because you're not calling first() on the query builder object, so you have an instance of Builder (which does not have a $movimentoProdutoUnidade property) instead of a Movimento model:
$movimento = Movimento::where('unidade_ori_id', 3)->first();
$movimento_produto_unidade = $movimento->movimentoProdutoUnidade;
However, if you want all MovimentoProdutoUnidade, try thinking "backwards":
$movimento_produto_unidade = MovimentoProdutoUnidade::whereHas('movimento', function ($query) {
return $query->where('unidade_ori_id', 3);
})
->get();
As stated in the comment i made, try using first function like this:
Movimento::where('unidade_ori_id', 3)->first()->movimentoProdutoUnidade;
Remember always after the condition use get(), first() or find() functions to pull the data from the database.
Take a look to this link

laravel make a model have an attribute with value

I have a model called template and field template - when being called it doesn't exist, so how do I create a property or attribute called template when calling it this is being called through ajax. I tried making an accessor but it's not creating the attribute 'template' getTemplateAttribute($value) so I made a with('template') and I can't seem to create the attribute template in my model when being called.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Template extends Model
{
protected $table = 'templates';
protected $fillable = ['title', 'directory', 'filename', 'created_at', 'updated_at'];
public function template() {
$this->attributes['template'] = 'test';
}
}
// and when calling it
public function show(Template $template)
{
$template = Template::findOrFail($template->id)->with('template');
return $template;
}
Use appends in model.. then use getAppendTypeAttribute(); the AppendType must be exact name as appends value..
class Template extends Model
{
protected $table = 'templates';
protected $fillable = ['title', 'directory', 'filename', 'created_at', 'updated_at'];
protected appends = ['template'];
public function getTemplateAttribute() {
return "test";
}
}
then
$template = Template::findOrFail($template->id);
return $template->template;

Laravel default user_id attribute in Model

I have a model
class Foo extends Model
{
protected $fillable = [
'name',
'user_id'
];
}
I would like to set Auth::user()->id by default to user_id column. So I added:
class Foo extends Model
{
protected $fillable = [
'name',
'user_id'
];
public function setUserIdAttribute()
{
$this->attributes['user_id'] = Auth::user()->id;
}
}
And from my controller I'm calling for Foo::create($data) without user_id key.
But it doesn't work as expected. store() gives Integrity constraint violation because of user_id is missing. (User already logged in to achieve create page)
i cannot find official documentation about model-observers for Laravel 5.6. but you can still do it by this code
public static function boot()
{
parent::boot(); // TODO: Change the autogenerated stub
// it will automatically add authenticate user to created_by column of selected model
static::creating(function ($model){
$model->created_by = auth()->user()->id;
});
}
You provide an example where you used accessors.
https://laravel.com/docs/5.1/eloquent-mutators#accessors-and-mutators
From official doc:
The accessor will automatically be called by Eloquent when attempting to retrieve the value of first_name:
If you want to set default value for some attributes you need to use Observers.
<?php
// file app/models/Foo.php
namespace App\Models;
use App\Observers\FooObserver;
class Foo extends Model
{
protected $fillable = [
'name',
'user_id'
];
public static function boot() {
parent::boot();
parent::observe(new FooObserver);
}
}
<?php
// file app/observers/FooObserver.php
namespace App\Observers;
use App\Models\Foo;
class FooObserver {
public function creating(Foo $model) {
$this->user_id = Auth::user()->id;
}
}
About model observers in official doc:
https://laravel.com/docs/5.0/eloquent#model-observers

Laravel Mutators with Constructor?

Ill have a problem because my mutators never get called when ill use an constructor:
Like this:
function __construct() {
$this->attributes['guid'] = Uuid::generate(4)->string;
}
public function setDateAttribute($date) {
dd($date); // Never gets called
}
Ill already found out, that the mutators would ne be called when ill use an constructor, so i should use:
public function __construct(array $attributes = array()){
parent::__construct($attributes);
$this->attributes['guid'] = Uuid::generate(4)->string;
}
public function setDateAttribute($date) {
dd($date); // now its getting called
}
But so ill get the following error:
array_key_exists() expects parameter 2 to be array, null given
But i dont know where? Can anyone help me out how to create a default value (like a UUID) for a specific column, and use mutators in the same class?
Edit: Thanks Martin Bean for your help, but i am now getting the following error:
Cannot declare class App\Uuid because the name is already in use
I have tried:
Creating a File called "Uuid.php" in /app/ -> /app/Uuid.php
With this content:
<?php namespace App;
use Webpatser\Uuid\Uuid;
trait Uuid
{
public static function bootUuid()
{
static::creating(function ($model) {
$model->uuid = Uuid::generate(4)->string();
});
}
}
Changed my Model to:
<?php namespace App;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
class Task extends Model {
use \App\Uuid;
Thank you very much!
Edit 2:
Ill tried it this way:
class Task extends Model {
protected $table = 'tasks';
protected $fillable = ['..... 'date', 'guid'];
public function setGuidAttribute($first=false){
if($first) $this->attributes['guid'] = Uuid::generate(4)->string;
}
TaskController:
public function store() {
$input = Request::all();
$input['guid'] = true;
Task::create($input);
return redirect('/');
}
Works fine, but when ill use:
public function setDateAttribute(){
$this->attributes['date'] = date('Y-m-d', $date);
}
In Task.php ill get:
Undefined variable: date
EDITED:
based on your comment:
i would like to set a field on first insert
use Uuid; //please reference the correct namespace to Uuid
class User extends Model{
protected $fillable = [
'first_name',
'email',
'guid' //add guid to list of your fillables
]
public function setGuidAttribute($first=false){
if($first) $this->attributes['guid'] = Uuid::generate(4)->string;
}
}
Later:
$user = User::create([
'guid' => true, //setAttribute will handle this
'first_name' => 'Digitlimit',
'email" => my#email.com
]);
dd($user->guid);
NB: Remove the __construct() method from your model
Mutators are called when you try and set a property on the model—they’re invoked via the __get magic method. If you manually assign a property in a method or constructor, then no mutators will ever be called.
Regardless, you should not be creating constructors on Eloquent model classes. This could interfere with how Eloquent models are “booted”.
If you need to set an UUID on a model then I’d suggest using a trait that has its own boot method:
namespace App;
trait Uuid
{
public static function bootUuid()
{
static::creating(function ($model) {
$model->uuid = \Vendor\Uuid::generate(4)->string();
});
}
}
You apply the trait to your model…
class SomeModel extends Model
{
use \App\Uuid;
}
…and now each time a model is created, a UUID will be generated and stored in the database with your model.

Resources