Laravel Nova action models empty - laravel

Here is my action.
public function actions(Request $request)
{
return [
new ApprovedUserAction,
(new RejectUserAction)->make()->standalone(),
];
}
This is my action code.
{
Log::info('test',['test' => $models]);
Log::info('test',['field' => $fields]);
foreach ($models as $model) {
Log::info("here);
$actionEvent = ActionEvent::forResourceUpdate(auth()->user(), $model);
$model->update(['status' => 'reject']);
$actionEvent->save();
}
return $models;
// return Action::message('You have been Updated');
}
Why the models' values are empty??
I want to update the selected values, but the models return an empty array.

When its a standalone action these fields are omitted since it works on a whole resource and not selected records.
There are a few solutions here but i think creating two actions, one for the whole resource if you need a standalone and one for a collection of models if you need to select them.
Unless nova 4 released the other day has a better solution.
Here is link to relevant documentation for nova 3.
https://nova.laravel.com/docs/3.0/actions/registering-actions.html#standalone-actions

Related

laravel 5.6 Eloquent : eloquent relationship model creation issue

in my controller i create an Eloquent Model Instance passign throug a relation. The model is loaded on controller's __construct, that's why is present a $this->store and not a $store.
public function index()
{
if (is_null($this->store->gallery)) {
$this->store->gallery()->create([
'title' => 'gallery_title,
'description' => 'gallery_description',
]);
}
$gallery = $this->store->gallery;
dd($gallery);
return view('modules.galleries.index', compact('gallery'));
}
Simply if a store's gallery is not present yet, let's create it.
The first time i print out my dd() is ALWAYS null, if i reload the page the dd() show correctly my gallery model.
The things is weird for me, seems like the first time the creation is done but not ready... I can work around but why this code doesn't work the first time?
Help is very appreciate.
Relationship codes: on gallery ....
public function store()
{
return $this->belongsTo(Store::class);
}
on store...
public function gallery()
{
return $this->hasOne(Gallery::class);
}
When using the $this->store->gallery()->create() method, the original method is not hydrated with the new value, you can simply do a
$gallery = $this->store->refresh()->gallery;
OR
$gallery = $this->store->load('gallery')->gallery;
if you want to make your code cleanner you can do that in your Store Model:
public function addGallery($gallery){
$this->gallery()->create($gallery);
return $this->load('gallery')->gallery;
}
And that in your controller:
$gallery = $this->store->addGallery([
'title' => 'gallery_title',
'description' => 'gallery_description',
]);
and voila ! You have your gallery ready to be used :)
It's the lazy load part of Eloquent. basicly, when you tested for it with is_null($this->store->gallery) it sets it to that value.
when you tried to recover it again, it did not do the DB query, it just loaded the value already present (null).
after creation you need to force reload the relation:
$this->store->load('gallery');
or
unset($this->store->gallery);
or
$gallery = $this->store->gallery()->get();

How to ignore field from database operation in Laravel Nova

I am developing a Web Application using Laravel Nova. Laravel Nova is quite new. I am now having problem with database relationship and Fields. I like to ignore a field from database operations. This is my scenario.
In the Job resource, I have this fields method
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name', 'name'),
Text::make('Email', 'email'),
Select::make('Contract Types')->options($array_of_options)//I want to ignore this field
];
}
As you can see, the last field is Contract Types.
When I create a new job from Dashboard, it is throwing error because there is no contract_types column on the Job model. I like to ignore that field from database operation. How can I get it?
The accepted answer is not completely correct. It prevents storing the value in the database but also completely hides the field in the form. In some weird cases you might want to show a field that is not stored.
My suggestion would be to add the following to the resource (or put in somewhere more re-usable if you want this in multiple resources):
public static function fill(NovaRequest $request, $model)
{
return static::fillFields(
$request, $model,
(new static($model))->creationFieldsWithoutReadonly($request)->reject(function ($field) use ($request) {
return in_array('ignoreOnSaving', $field->meta);
})
);
}
In the relevant field(s) you could than add:
->withMeta(['ignoreOnSaving'])
This will give you a field to fill without saving it in the model.
According to the docs https://nova.laravel.com/docs/1.0/resources/fields.html#showing-hiding-fields
Select::make('Contract Types')
->options($array_of_options)
->hideWhenCreating()
You can make an own custom handling of the Field data, just use fillUsing() method of the Field class. An example
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name', 'name'),
Text::make('Email', 'email'),
Select::make('Contract Types', 'unique_key_for_model')
->options($array_of_options)
->fillUsing(function(NovaRequest $request, $model, $attribute, $requestAttribute) {
/*
$request->input('unique_key_for_model') // Value of the field
$model->unique_key_for_model // DOES NOT exists, so no errors happens
*/
// or just return null;
return null;
}),
];
}

Laravel oneToMany accessor usage in eloquent and datatables

On my User model I have the following:
public function isOnline()
{
return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}
The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.
In my controller I am doing the following:
$builder = App\User::query()
->select(...fields I want...)
->with('isOnline')
->ofType($realm);
return $datatables->eloquent($builder)
->addColumn('info', function ($user) {
return $user->isOnline;
}
})
However I don't get the value of 'rtype' for the users in the table and no errors.
It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.
The correct approach is to only return the HasMany object from your method and it will be treated as a relation.
public function accounts()
{
return $this->hasMany('App\Accounting', 'userid');
}
Then if you want an isOnline helper method in your App\User class you can add one like this:
public function isOnline()
{
// This gives you a collection of \App\Accounting objects
$usersAccounts = $this->accounts;
// Do something with the user's accounts, e.g. grab the last "account"
$lastAccount = $usersAccounts->last();
if ($lastAccount) {
// If we found an account, return the rtype column
return $lastAccount->rtype;
}
// Return something else
return false;
}
Then in your controller you can eager load the relationship:
$users = User::with('accounts')->get(['field_one', 'field_two]);
Then you can do whatever you want with each App\User object, such as calling the isOnline method.
Edit
After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.
So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:
// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');
This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns
Thanks Jonathon
USER MODEL
public function accounting()
{
return $this->hasMany('App\Accounting', 'userid', 'userid');
}
public function isOnline()
{
$rtype = $this->accounting()
->latest('ts')
->limit(1)
->pluck('rtype')
->first();
if ($rtype == 'Alive') {
return true;
}
return false;
}
CONTROLLER
$builder = App\User::with('accounting:rtype')->ofType($filterRealm);
return $datatables->eloquent($builder)
->addColumn('info', function (App\User $user) {
/*
THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
*/
$info[];
if ($user->isOnline()) {
$info[] = 'Online';
} else {
$info[] = 'Offline';
}
return implode(' ', $info);
})->make();

Returning custom variable in Settings - Laravel Spark

I have setup Spark and I have created my custom view in Settings - Students (assume User object is actually a teacher). I have also created migration and model Student.
Now http://spark.app/settings/students returns the page successfully. At this point, I need to return data from backend. I investigated Spark\Http\Controllers\Settings\DashboardController#show - which is the method returning the 'settings' view, however this doesn't return any data to view using ->with('user', $user)
But, as mentioned in Docs, :user="user" :teams="teams" :current-team="currentTeam" already available out of the box.
Where and how does Spark returns these values to /settings? And How do I make my Student object available likewise?
Now, if I want to return my Student object to front-end, I have 2 choices.
1) edit Spark\Http\Controllers\Settings\DashboardController
2) I think Spark\InitialFrontendState is the place where Spark returns these objects user, teams, currentTeam. This approach is something I've seen for the first time to be honest and I didn't really understand how it works.
So how should I achieve in Spark, something as simple as :
return view('spark::settings')->with('student', $student); ?
Add a new route and set up your own Controller & own view
web.php
Route::get('/settings/students', 'SettingsStudentController#index');
SettingsStudentController.php
class SettingsStudentController extends Controller {
public function __construct() {
$this->middleware('auth');
}
public function index(Request $request) {
$user = Auth::user();
$student = STUDENTCLASS::whatever();
return view('yourstudentview', ['student' => $student , 'user' => $user]);
}
}

exclude certain records from laravel scout/algolia

I am using laravel scout to upload records for searching in algolia. I have added the searchable trait to my model, and everything is working fine.
There is a case now where I don't want to add certain records to my index if they have set status I.E UNPUBLISHED.
is there away I can evaluate the status field and decide if I want the model to be uploaded to the index?
Just use $model_name->unsearchable() to remove it from your Algolia index.
See "Removing Records" in the documentation for more details: https://laravel.com/docs/5.3/scout#removing-records
You can use method toSearchableData() and in case the status is Unpublished, just return empty array and the record will be skipped.
Otherwise just return $this->toArray().
It will do the trick.
Say we have a Post model, with a boolean published attribute, and a model factory to seed our table as follows:
$factory->define(App\Post::class, function (Faker\Generator $faker) {
$tile = $faker->realText(50);
$date = $faker->dateTime;
return [
'title' => $tile,
'body' => $faker->realText(500),
'published' => $faker->boolean(80),
'created_at' => $date,
'updated_at' => $date
];
});
Let's say we will seed 10 records.
public function run()
{
factory(App\Article::class, 10)->create();
}
If we tried to exclude unpublished records within the toSearchableArray() method, as suggested:
public function toSearchableArray()
{
if (! $this->published) {
return[];
}
// ...
}
When seeding the posts table, instead of ignoring unpublished records by returning an empty array, scout will keep asking the model factory for a published model.
For example, if two of the seeded records were randomly unpublished, scout would index all 10 records (instead of 8) anyway, replacing the unpublished ones by a new model factory (with a published set attribute). Thus causing to have two inexistent (on our table) records in the algolia index. Quite confusing.
The "neatest" way around this I could come up with, was to listen to the saved/updated events (saving/updating won't cut it) in the model's boot method.
protected static function boot()
{
static::saved(function ($model) {
if (! $model->published) {
$model->unsearchable();
}
});
static::updated(function ($model) {
if (! $model->published) {
$model->unsearchable();
}
});
parent::boot();
}
Check out this question. This problem has been solved in the new version of Scout
Adding Index to Laravel Scout Conditionally (Algolia)

Resources