Laravel Nova Action Fields - laravel

EDIT:
in novas ActionEvent.php class i edited the two rows fields and exceptions for the forResourceUpdate function:
Whats actually strange now my resource is updated but there is nothing in the ACTION EVENT table.
public static function forResourceUpdate($user, $model)
{
return new static([
'batch_id' => (string) Str::orderedUuid(),
'user_id' => $user->getKey(),
'name' => 'Update',
'actionable_type' => $model->getMorphClass(),
'actionable_id' => $model->getKey(),
'target_type' => get_class($model),
'target_id' => $model->getKey(),
'model_type' => get_class($model),
'model_id' => $model->getKey(),
'fields' => 'test',
'status' => 'finished',
'exception' => 'test',
]);
}
so i just installed Nova set up some Resources, it shows everything fine, but when i try to update any of them, i get a Database error that i cant insert NULL into ACTION_EVENT.FIELDS.
https://nova.laravel.com/docs/1.0/actions/defining-actions.html#action-fields
The Doc says i can define some fields in the Actions fields function , but i didnt generate any Action class not i want to. I think its some sort of default action logging?
Can i turn it off, or do i have to add some Fields somewhere?
<?php
namespace App\Nova;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Http\Requests\NovaRequest;
class Chain extends Resource
{
public static $category = "Stammdaten";
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = 'App\Model\System\Partner\Chain';
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'id';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id',
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
And The Model:
class Chain extends Model
{
use SoftDeletes;
use ObservantTrait;
use TranslationTrait;
protected $primaryKey = 'partner_chain_id';
protected $table = 'tbl_prm_partner_chain';
public $sequence = 'seq_partner_chain_id';
const CREATED_BY = 'insert_user';
const CREATED_AT = 'insert_timestamp';
const UPDATED_BY = 'update_user';
const UPDATED_AT = 'update_timestamp';
const DELETED_BY = 'delete_user';
const DELETED_AT = 'delete_timestamp';
protected $fillable = ['name_text', 'partner_type_id'];
protected $dates = ['delete_timestamp', 'insert_timestamp'];
thats all its quit simple, thats why i have no Clue right now where i am going wrong.

Related

Laravel Nova page detail not found due to The relationship

I am trying to test the tool I have been created. When I used relationship field in one of my resource, the page detail on this resource give me Not found.
/* My Relationship field */ (Ticket Resource)
HasMany::make(__('Replies'), 'replies',Reply::class)
/* Include */
use TicketWhmcs\TicketWhmcsPackage\Nova\Reply;
/* Ticket Model */
<?php
namespace TicketWhmcs\TicketWhmcsPackage\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use TicketWhmcs\TicketWhmcsPackage\Traits\API;
use TicketWhmcs\TicketWhmcsPackage\Models\TicketReplay;
class Ticket extends Model
{
use HasFactory, API;
protected $table = 'tickets';
protected $fillable = [
'tid',
'user_id',
'dept_id',
'subject',
'message',
'priority',
'status',
'admin',
];
public function department()
{
return $this->belongsTo(Department::class, 'dept_id', 'id');
}
/**
* Get all of the replies for the Ticket
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function replies()
{
return $this->hasMany(TicketReplay::class);
}
}
/* My resource */
namespace TicketWhmcs\TicketWhmcsPackage\Nova;
My Reply Resource
<?php
namespace TicketWhmcs\TicketWhmcsPackage\Nova;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;
class Reply extends Resource
{
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = \TicketWhmcs\TicketWhmcsPackage\Models\TicketReplay::class;
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'id';
/* Sort */
public static $sort = [
'id' => 'desc',
];
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id', 'admin',
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make(__('ID'), 'id')->sortable(),
Text::make(__('Message'), 'message')->hideFromIndex(),
Text::make(__('Message'), 'message')->displayUsing(function ($value) {
return Str::limit($value, 50);
})->onlyOnIndex(),
Text::make(__('Author'), 'admin')->displayUsing(function ($value) {
if ($value) {
return 'Admin';
} else {
return 'You';
}
})->hideWhenCreating(),
Text::make('Last Update', 'updated_at')
->displayUsing(function ($lastActive) {
if ($lastActive === null) {
return null;
}
return $lastActive->diffForHumans();
})->hideWhenCreating(),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
public function authorizedToUpdate(Request $request)
{
return false;
}
public function authorizedToDelete(Request $request)
{
return false;
}
public static function indexQuery(NovaRequest $request, $query)
{
if (empty($request->get('orderBy'))) {
$query->getQuery()->orders = [];
return $query->orderBy(key(static::$sort), reset(static::$sort));
}
return $query;
}
}
I register My resource in NovaServiceProvider
public function resources()
{
Nova::resources([
Reply::class
]);
}
And it's worked!

Laravel model attribute returning empty array

I have a model called Address. It has an 'additional' attribute. Although the attribute is filled, the model returns an empty array. I use an API resource to get the data.
This is the Address model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Address extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'addresses';
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model's ID is auto-incrementing.
*
* #var bool
*/
public $incrementing = true;
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps = false;
/**
* The database connection that should be used by the model.
*
* #var string
*/
protected $connection = 'solarium';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//
];
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = [];
/**
* The model's default values for attributes.
*
* #var array
*/
protected $attributes = [
//
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
//
];
public function addressable()
{
return $this->morphTo();
}
}
This is the Address API resource:
<?php
namespace App\Http\Resources;
use App\Models\Address;
use Illuminate\Http\Resources\Json\JsonResource;
class AddressResource extends JsonResource
{
/**
* The resource that this resource collects.
*
* #var string
*/
public $collects = Address::class;
/**
* Indicates if the resource's collection keys should be preserved.
*
* #var bool
*/
public $preserveKeys = true;
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'cep' => $this->cep,
'street' => $this->street,
'number' => $this->number,
'district' => $this->district,
'city' => $this->city,
'state' => $this->state,
'additional' => $this->additional,
];
}
}
As I said, the 'additional' attribute returns an empty array although it is filled with a string value.
The JsonResource has a public property named additional which has a default value of [], an empty array. That is what you are accessing since $this->additional is asking for that property. This is not forwarding that access to the model (resource) since this is an accessible property on this instance, (how PHP's OOP works).
You would probably have to access the underlying resource from the property of the JsonResource to then access that particular property (attribute):
$this->resource->additional

Custom cast ignored after updating model

After I update my model, the cast is ignored and an old value that comes from classCastCache is shown.
I'm getting a Illuminate\Http\Testing\File instead of 'GETTING'.
Create a custom cast:
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class Image implements CastsAttributes
{
/**
* Cast the given value.
*
* #param \Illuminate\Database\Eloquent\Model $model
* #param string $key
* #param mixed $value
* #param array $attributes
* #return mixed
*/
public function get($model, $key, $value, $attributes)
{
return 'GETTING';
}
/**
* Prepare the given value for storage.
*
* #param \Illuminate\Database\Eloquent\Model $model
* #param string $key
* #param mixed $value
* #param array $attributes
* #return mixed
*/
public function set($model, $key, $value, $attributes)
{
return 'SETTING';
}
}
Apply it to a model:
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Casts\Image;
class Product extends Model
{
use HasFactory;
/**
* Mass assignable attributes.
*
* #var string[]
*/
protected $fillable = [
'name',
'image',
];
/**
* Model's attribute casting.
*
* #var array
*/
protected $casts = [
'image' => Image::class,
];
}
Create a test for it:
/** #test */
public function it_can_change_product_image()
{
Storage::fake();
$business = Business::factory()->create();
$product = Product::factory()->for($business)->create();
$this->authenticate($business->owner); // Helper to authenticate with Sanctum. Ignore.
// The important part here, sending a fake image.
$response = $this->putJson(route('v1.products.update', $product), [
'image' => UploadedFile::fake()->image('example.jpg'),
]);
$response->assertOk(); // Among other tests that are hidden due demo purposes.
}
Create a Controller action to update the value of it.
/**
* Update the specified resource in storage.
*
* #param UpdateRequest $request
* #param Product $product
* #return ProductResource
*/
public function update(UpdateRequest $request, Product $product): ProductResource
{
// The custom request validator checks for:
// 'image' => ['sometimes', 'file', 'max:1024', 'image', 'mimes:jpg,bmp,png']
// This should update the product image based on the cast.
// The current DB value should be `SETTING`.
$product->update($request->validated());
// This should be `GETTING`.
// Instead, it is: Illuminate\Http\Testing\File
dd($product->image);
// a BAD workaround is to:
$product->refresh();
// This is the correct value `GETTING`.
dd($product->image);
}

How to implement many to many nova resource without building custom tool

I am currently building a timetable generation system, I have these models below which are Subject and Teacher as the two main models with their nova resources, I have created a pivot model SubjectAllocation (has a nova resource) with a pivot table subject_allocations with fields teacher_id and subject_id. I would like to be able to use SubjectAllocation nova resource to select a teacher and allocate multiple subjects to this teacher but currently, I have no lack of it. Tried pulling in this package dillingham/nova-attach-many to attach to the SubjectAllocation model and this package to pick teachers records sloveniangooner/searchable-select but it cannot store data in the pivot table.
Subject Allocation Resource
<?php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\BelongsToMany;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Http\Requests\NovaRequest;
use NovaAttachMany\AttachMany;
use Sloveniangooner\SearchableSelect\SearchableSelect;
class SubjectAllocation extends Resource
{
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = 'App\SubjectAllocation';
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'id';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id',
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
SearchableSelect::make('Teacher', 'teacher_id')->resource("teachers"),
AttachMany::make('Subjects')
->showCounts()
->help('<b>Tip: </b> Select subjects to be allocated to the teacher'),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
Fields Methods in Subject Resource
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Subject Name', 'name')
->withMeta(['extraAttributes' => ['placeholder' => 'Subject Name']])
->sortable()
->creationRules('required', 'max:255', 'unique:subjects,name')
->updateRules('required', 'max:255'),
Text::make('Subject Code', 'code')
->withMeta(['extraAttributes' => ['placeholder' => 'Subject Code']])
->sortable()
->creationRules('required', 'max:255', 'unique:subjects,code')
->updateRules('required', 'max:255')
,
Textarea::make('Description')
->nullable(),
BelongsToMany::make('Teachers'),
];
}
Fields method in Teacher Resource
public function fields(Request $request)
{
return [
ID::make()->sortable(),
BelongsTo::make('User')
->searchable(),
Text::make('First Name', 'first_name')
->withMeta(['extraAttributes' => ['placeholder' => 'First Name']])
->sortable()
->rules('required', 'max:50'),
Text::make('Middle Name', 'middle_name')
->withMeta(['extraAttributes' => ['placeholder' => 'Middle Name']])
->sortable()
->nullable()
->rules('max:50'),
Text::make('Last Name', 'last_name')
->withMeta(['extraAttributes' => ['placeholder' => 'Last Name']])
->sortable()
->rules('required', 'max:50'),
Text::make('Teacher Code', 'teacher_code')
->withMeta(['exraAttributes' => [ 'placeholder' => 'Teacher Code']])
->sortable()
->creationRules('required', 'max:50', 'unique:teachers,teacher_code')
->updateRules('required', 'max:50'),
BelongsToMany::make('Subjects'),
];
}
Any suggestion on how I can make it work or a better solution, would appreciate very much
Without build custom tool, use following method:
// app\Nova\SubjectAllocation.php
public function fields(Request $request)
{
return [
ID::make()->sortable(),
// SearchableSelect::make('Teacher', 'teacher_id')->resource("teachers"),
SearchableSelect::make('Teacher', 'teacher_id')->resource(\App\Nova\Teacher::class)
->displayUsingLabels(),
AttachMany::make('Subjects','subject_id')
->showCounts()
->help('<b>Tip: </b> Select subjects to be allocated to the teacher')
->fillUsing(function($request, $model, $attribute, $requestAttribute) {
$a = json_decode($request->subject_id, true);
$teacher = \App\Teacher::find($request->teacher_id);
if(count($a)==0){
// Error processing because no subject is choosen
}else if(count($a)==1){
$model['subject_id'] = $a[0];
}else{
$model['subject_id'] = $a[0];
array_shift ($a); // Remove $a[0] in $a
$teacher->subjects()->sync(
$a
);
}
})
];
}

ErrorException in SessionGuard.php | Getting error when trying to register user while creating new order

I want user to register and also buy a package. To do that I took input for registration details and package details. Now when I'm processing order to save package details in session and register, I get this error : Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\View\View given, called in C:\xampp\htdocs\rename\app\Traits\OrderRegister.php on line 63 and defined. I'm using an trait to register user and return back to function when registration is complete.
OrderController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Package;
use App\ListingType;
use Illuminate\Support\Facades\Auth;
use App\Order;
use Carbon\Carbon;
use App\Traits\OrderRegister;
class OrderController extends Controller
{
use OrderRegister;
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index($type)
{
$listingtype = ListingType::where('type', '=', $type)->first();
if ($listingtype) {
$packages = $listingtype->packages()->get();
return view('packages.index', compact('packages'));
}
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create($id)
{
$package = Package::where('id', '=', $id)->first();
if (Auth::check()) {
return view('order.create_loggedin', compact('package'));
}
else {
return view('order.create_register', compact('package'));
}
}
/**
* Process a new order request. Store order values in session.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function process(Request $request)
{
$order = ['package_id' => $request->package_id, 'order_qty' => $request->no_of_listing];
session(['order' => $order]);
if (Auth::guest()) {
return $this->register($request); // need to check session for orders available in OrderRegister trait.
}
return $this->store($request);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if($request->session()->has('order')) {
$package = Package::where('id', '=', $request->package_id )->first();
if($request->user() == Auth::user()) {
for( $n=1;$n<=$request->no_of_listing;$n++) {
$order = new Order;
$order->package_id = $request->package_id;
$order->user_id = Auth::user()->id;
$order->expire_at = Carbon::now()->modify('+'.$package->duration_in_months.' months');
$order->save();
}
return redirect('/');
}
}
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
trait : OrderRegister.php
<?php
namespace App\Traits;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Validator;
trait OrderRegister
{
use RedirectsUsers;
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'username' => 'required|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'username' => $data['username'],
'password' => bcrypt($data['password']),
]);
$user->profile()->save(new UserProfile);
return $user;
}
/**
* Execute the job.
*
* #return void
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
Auth::guard($this->getGuard())->login($this->create($request->all()));
return $this->store($request);
}
/**
* Get the guard to be used during registration.
*
* #return string|null
*/
protected function getGuard()
{
return property_exists($this, 'guard') ? $this->guard : null;
}
}
I could not find any solution for this error so created my own thread for the first time please someone help.
It throws an error because you are trying to login a vue.
in your OrderController.php you are using create method which return a view.
this method will override the create method on your trait.
So you have something like this :
Auth::guard($this->getGuard())->login(/* A view */);
you can at least rename the method on the trait from create to createUser for example.
then you call it from the guard like this :
Auth::guard($this->getGuard())->login($this->createUser($request->all()));

Resources