I'm having some issues using Voyager. I can create Accessors to attributes, as described in the documentation. It works nicely to access the data, but I also have to create a Mutator to change the data before saving it. Apparently, there's no implementation by Voyager, so I tried to do it through Laravel way. It also works very nicely in common environments, but for some reason, there is a different behavior with Voyager.
The Mutator is called after the Accessor, even when only browsing:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
public function setNameAttribute($value){ // my mutator
$value = preg_replace("/[^a-zA-Z]/", '', $value);
$this->attributes['name'] = $value;
}
public function getNameBrowseAttribute(){ // my accessor
return $this->name . '...'; // example
}
}
What is happening:
When I access the browser of my Model, the getNameBrowseAttribute is called, as it should be, but after that, the setNameAttribute is called as well, which should not happen because I'm browsing, and not saving or updating the Model.
I tried to debug the code, and the last Voyager file called is a view, from voyager/storage/framework/views/, where $data is the Model:
if ($data->{$row->field.'_browse'}) {
$data->{$row->field} = $data->{$row->field.'_browse'}; // <-- this line
}
As you can see, it is calling a method with ...browse, and not set...
Any help is appreciated :)
You could try to do with model events. Use the saving event.
https://laravel.com/docs/8.x/eloquent#events
Related
i´m studying laravel but having some doubts..
Controller
namespace App\Http\Controllers;
use App\ItemNfe;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ItensNfeController extends Controller
{
public function edit($id,ItemNfe $itemNfe)
{
//i don´t want to have to make this select below
//$itemNfe = DB::table('itens_nfe')->where('id_itemnfe',$id)->get();
// dd($itemNfe); this dd() returns model attributes on few of my controllers only
return view...
}...
Model: (note i´m not using laravel convention but it´s informed)
namespace App;
use Illuminate\Database\Eloquent\Model;
class ItemNfe extends Model
{
protected $table = 'itens_nfe';
protected $primaryKey = 'id_itemnfe';
protected $fillable = [
'id_itemnfe','fk_venda', 'fk_produto'...
];
public function nfe()
{
return $this->belongsTo('App\Nfe'); //this is one diference among others models, but apparently doesn´t affects when i tested without this code.
}
}
The route i´m using is the same for everyone.. "resource routes"
At the first 2, i have the attributes returning, but not at the last one...
Route::resource('/usuarios', 'UsuariosController');
Route::resource('/nfes', 'NfesController');
Route::resource('/itensnfe', 'ItensNfeController');
The Url used is:
https://localhost/erpoverweb/public/itensnfe/1/edit
If needing more code please tell me... thanks!
If you don't want to manually search the database for the entry, you can use Laravel Container do perform a Dependency Injection. https://laravel.com/docs/7.x/container#introduction
public function edit(ItemNfe $itemNfe)
{
// Returns the model, and you didn't need to manually searched.
// Laravel automaticly injects this for you.
dd($itemNfe);
}
Sounds like you are looking for Route Model Binding (implicit at that). This requires that the route parameter name and the name of the parameter of the method signature for that route match.
public function edit(ItemNfe $itensnfe)
The resource route with resource name 'itensnfe' should make the parameter 'itensnfe'.
If you don't make these match you will just end up with Dependency Injection which would inject a new model instance.
Laravel 7.x Docs - Routing - Route Model Binding - Implicit Binding
I have a contact_info_scopes table and one of the scopes is 'Default', which is likely to be the most common scope called, so I'm creating an accessor
public function getDefaultScopeIdAttribute()
{
return $this::where('contact_info_scope', 'Default')
->first()
->contact_info_scope_uuid;
}
to get the defaultScopeId and wondering how I can new up the ContactInfoScope model and access that in one line. I know I can new it up:
$contactInfoScope = new ContactInfoScope();
and then access it:
$contactInfoScope->defaultScopeId;
but I would like to do this in one line without having to store the class in a variable. Open to any other creative ways of tackling this as well since an accessor may not really be ideal here! I'd be fine with just creating a public function (not as an accessor), but would have the same issue of calling that in one line. Thanks :)
You should be able to call the model and chain the value if you return the instance in its constructor method
(new ContactInfoScope)->defaultScopeID
Not tried it in Laravel but works in plain ol PHP
//LARAVEL
//write on model ----------------------------------
protected $appends = ['image'];
public function getImageAttribute()
{
$this->school_iMage = \DB::table('school_profiles')->where('user_id',$this->id)->first();
$this->studend_iMage = \DB::table('student_admissions')->where('user_id',$this->id)->first();
return $this;
}
//call form anywhere blade and controller just like---------------------------
auth()->user()->image->school_iMage->cover_image;
or
User::find(1)->image->school_iMage->cover_image;
or
Auth::user()->image->school_iMage->cover_image;
// you can test
dd( User::find(1)->image);
I'd like to be able to modify the Auth->user() data that Laravel 5.6 uses. I have table called settings with a column called user_id in it that corresponds to a user id.
I tried modifying app\User.php and adding a __construct function:
public function __construct() {
$this->settings = Settings::where('user_id',
Auth->user->id()
)->first();
}
And I created a file app\Settings.php with the following:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class settings extends Model
{
protected $table = "settings";
}
However I'm getting a user error on the Auth->user()->id line in User.php, although I'm sure thats the correct way to reference it?
How can I load the data from the settings table to the User class?
You can just use load() method to lazy load the relation:
auth()->user()->load('settings');
You need to do this just once per request, in a middleware for example. Then you'll be able to use the data in any part of your app:
{{ auth()->user()->settings->theme }}
Of course, to make this work you need to define relationship in the User model, for example:
public function settings()
{
return $this->hasOne(Settings::class);
}
Heey guys! I use Laravel 5.4, WAMP for localhost. I am struggling with the problem to call a Controller#methodName within my header.blade.php file, because I want to show in my header.blade.php file all notifications for the User. Normally I was getting all needed data with the help of routes in different pages. But for this case I need to call without using routes. Here is my code for my NotificationController:
class NotificationController extends Controller
{
public function getNotification(){
$notifications = Notification::where('user_id',Auth::user()->id)->get();
$unread=0;
foreach($notifications as $notify){
if($notify->seen==0)$unread++;
}
return ['notifications'=>$notifications, 'unread'=>$unread];
}
}
And I should receive all these data in my header file. I have used: {{App::make("NotificationController")->getNotification()}}
and {{NotificationController::getNotification() }} But it says Class NotificationController does not exist. Please heelp!
Instead of calling the controller method to get notifications, you can make a relationship method in your User model to retrieve all the notifications that belongs to the user and can use Auth::user()->notifications. For example:
// In User Model
public function notifications()
{
// Import Notification Model at the top, i.e:
// use App\Notification;
return $this->hasMany(Notification::class)
}
In your view you can now use something like this:
#foreach(auth()->user()->notifications as $notification)
// ...
#endforeach
Regarding your current problem, you need to use fully qualified namespace to make the controller instance, for example:
app(App\Http\Controllers\NotificationController::class)->getNotification()
Try using the full namespace:
For instance, App\Http\Controllers\NotificationController::getNotification
but of course, controllers aren't meant to be called the way you're using them. They're meant for routes. The better solution is to add a relationship in your user model like so:
public function notifications()
{
return $this->hasMany(Notification::class)
}
And then use this in your view like so:
#foreach(Auth::user()->notifications as $notification)
Are there callbacks in Laravel like:
afterSave()
beforeSave()
etc
I searched but found nothing. If there are no such things - what is best way to implement it?
Thanks!
The best way to achieve before and after save callbacks in to extend the save() function.
Here's a quick example
class Page extends Eloquent {
public function save(array $options = [])
{
// before save code
parent::save($options);
// after save code
}
}
So now when you save a Page object its save() function get called which includes the parent::save() function;
$page = new Page;
$page->title = 'My Title';
$page->save();
Adding in an example for Laravel 4:
class Page extends Eloquent {
public static function boot()
{
parent::boot();
static::creating(function($page)
{
// do stuff
});
static::updating(function($page)
{
// do stuff
});
}
}
Actually, Laravel has real callback before|after save|update|create some model. check this:
https://github.com/laravel/laravel/blob/3.0/laravel/database/eloquent/model.php#L362
the EventListener like saved and saving are the real callbacks
$this->fire_event('saving');
$this->fire_event('saved');
how can we work with that? just assign it to this eventListener example:
\Laravel\Event::listen('eloquent.saving: User', function($user){
$user->saving();//your event or model function
});
Even though this question has already been marked 'accepted' - I'm adding a new updated answer for Laravel 4.
Beta 4 of Laravel 4 has just introduced hook events for Eloquent save events - so you dont need to extend the core anymore:
Added Model::creating(Closure) and Model::updating(Closure) methods for hooking into Eloquent save events. Thank Phil Sturgeon for finally pressuring me into doing this... :)
In Laravel 5.7, you can create a model observer from the command line like this:
php artisan make:observer ClientObserver --model=Client
Then in your app\AppServiceProvider tell the boot method the model to observe and the class name of the observer.
use App\Client;
use App\Observers\ClientObserver;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Client::observe(ClientObserver::class);
}
...
}
Then in your app\Observers\ you should find the observer you created above, in this case ClientObserver, already filled with the created/updated/deleted event hooks for you to fill in with your logic. My ClientObserver:
namespace App\Observers;
use App\Client;
class ClientObserver
{
public function created(Client $client)
{
// do your after-model-creation logic here
}
...
}
I really like the simplicity of this way of doing it. Reference https://laravel.com/docs/5.7/eloquent#events
Your app can break using afarazit solution*
Here's the fixed working version:
NOTE: saving or any other event won't work when you use eloquent outside of laravel, unless you require the events package and boot the events. This solution will work always.
class Page extends Eloquent {
public function save(array $options = [])
{
// before save code
$result = parent::save($options); // returns boolean
// after save code
return $result; // do not ignore it eloquent calculates this value and returns this, not just to ignore
}
}
So now when you save a Page object its save() function get called which includes the parent::save() function;
$page = new Page;
$page->title = 'My Title';
if($page->save()){
echo 'Page saved';
}
afarazit* I tried to edit his answer but didn't work
If you want control over the model itself, you can override the save function and put your code before or after __parent::save().
Otherwise, there is an event fired by each Eloquent model before it saves itself.
There are also two events fired when Eloquent saves a model.
"eloquent.saving: model_name" or "eloquent.saved: model_name".
http://laravel.com/docs/events#listening-to-events