I'm using Laravel Nova 3 Queued Actions.
I have over 25K records in my table.
I want to Laravel Nova Action create new job only if model has attribute status == 1.
I tried to use continue in foreach loop but it does'nt work.
<?php
namespace App\Nova\Actions;
use App\Http\Services\UserService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Collection;
use Laravel\Nova\Actions\Action;
use Laravel\Nova\Fields\ActionFields;
class UserSynchronization extends Action implements ShouldQueue
{
use InteractsWithQueue, Queueable;
public $name = 'Synchronize User';
public static $chunkCount = 1;
public $withoutActionEvents = true;
public function __construct()
{
$this->connection = 'database';
//$this->queue = 'default';
}
/**
* Perform the action on the given models.
*
* #param \Laravel\Nova\Fields\ActionFields $fields
* #param \Illuminate\Support\Collection $models
* #return mixed
*/
public function handle(ActionFields $fields, Collection $models)
{
foreach ($models as $model) {
if (!$model->status !== 1) {
continue;
}
UserService::synchronize($model);
}
return Action::message('Users have been successfully synchronized');
}
/**
* Get the fields available on the action.
*
* #return array
*/
public function fields()
{
return [];
}
}
Create record in jobs table only if model->status === 1
Related
I have used the Mission model as:
use App\Models\Mission;
and it's located there for sure, locally it's working fine and no errors occur. But, on the staging environment it shows the error above. any command I should run on the staging environment ? . I have tried: php artisan optimize:clear but problem persist to occur
Error:
Error
<?php
namespace App\Http\Controllers\ServiceProvider;
use App\DataTables\ProjectDataTable;
use App\Http\Requests\CreateProjectRequest;
use App\Http\Requests\UpdateProjectRequest;
use App\Models\Project;
use App\Notifications\ProjectStatusChanged;
use App\Repositories\ProjectRepository;
use Exception;
use Illuminate\Support\Facades\Auth;
use Flash;
use App\Http\Controllers\AppBaseController;
use App\Models\Mission;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Response;
class ProjectController extends AppBaseController
{
/** #var ProjectRepository */
private $projectRepository;
/**
* ProjectController constructor.
* #param ProjectRepository $projectRepo
*/
public function __construct(ProjectRepository $projectRepo)
{
$this->projectRepository = $projectRepo;
}
/**
* Display a listing of the Project.
*
* #return View
* #throws AuthorizationException
*/
public function index()
{
$this->authorize('viewAny', Project::class);
$perPage = request('per-page', 5);
$search = request('search');
$projects = Project::orderByDesc('created_at')
->where('service_provider_id', Auth::user()->service_provider->id)
->search($search)
->paginate($perPage);
return view('projects.index', compact('projects'));
}
/**
* Display the specified Project.
*
* #param $slug
*
* #return Application|RedirectResponse|Redirector
* #throws AuthorizationException
*/
public function show($slug)
{
$project = $this->projectRepository->findBySlug($slug);
$allSites = collect();
$sitesIds = []; //to prevent duplicate sites
$missionsCompleted = $project->missions->where('status', '!=' , Mission::STATUS_COMPLETED)->count() ? false : true;
foreach ($project->missions as $mission) { //store all project's site in an array
if (in_array($mission->site->id, $sitesIds))
continue;
array_push($sitesIds, $mission->site->id);
$allSites->push($mission->site);
}
$this->authorize('view', $project);
if (empty($project)) {
Flash::error('Project not found');
return redirect(route('projects.index'));
}
return view('projects.show')->with([
'project'=>$project,
'allSites'=>$allSites,
'missionsCompleted'=>$missionsCompleted,
]);
}
}
Use alias in namespace:
use App\Models\Mission as MyMission;
I've created a broadcast channel App.Models.Admin.Notify where all the admin users will be subscribed to this channel by default.
<?php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('App.Models.Admin.Notify', function ($m) {
return !is_null($m) && $m->getMorphClass() === 'admin';
});
And this is the Notifications/Base.php where i've set ['database', 'broadcast', OneSignal::class] as notification channels
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Notifications\Messages\BroadcastMessage;
use NotificationChannels\OneSignal\OneSignalMessage;
use App\Channels\OneSignal;
abstract class Base extends Notification implements ShouldBroadcast, ShouldQueue
{
use Queueable;
public $model;
protected string $icon;
public function __construct(mixed $m = null)
{
$this->model = $m;
}
/**
* Get notify id
*
* #return string
*/
protected function getNotifyId(): string
{
return $this->id;
}
/**
* Get icon path
*
* #return string
*/
protected function getIcon(): string
{
return asset('favicon.ico');
}
/**
* Get notification link
*
* #return string
*/
protected function getLink(): string
{
return asset('favicon.ico');
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return \App\Channels\PusherBeams\PusherMessage
*/
public function via($notifiable)
{
return [
'database',
'broadcast',
OneSignal::class
];
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return array_merge(
[
'link' => $this->getLink(),
'icon' => $this->getIcon(),
],
$this->getData($notifiable)
);
}
/**
* Get data of message.
*
* #param mixed $notifiable
* #return array
*/
protected function getData($notifiable)
{
return [
'title' => 'hello',
'body' => 'world'
];
}
/**
* Create onesignal message of Web
* #param mixed $notifiable
* #return \NotificationChannels\OneSignal\OneSignalMessage
*/
public function toWeb($notifiable)
{
$data = $this->toArray($notifiable);
return OneSignalMessage::create()
->setSubject($data['title'])
->setBody($data['body'])
->setUrl($data['link']);
}
/**
* Create onesignal message of Android
* #param mixed $notifiable
* #return \NotificationChannels\OneSignal\OneSignalMessage
*/
public function toAndroid($notifiable)
{
$data = $this->toArray($notifiable);
return OneSignalMessage::create()
->setSubject($data['title'])
->setBody($data['body'])
->setData('url', str_replace('https://', 'gamepts://', $data['link']));
}
/**
* Websocket message
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\BroadcastMessage
*/
public function toBroadcast($notifiable)
{
return (new BroadcastMessage($this->toArray($notifiable)))->onQueue('pusher');
}
}
So this is the basic setup for my Notifications and broadcasting.
I've a job which runs every minutes and if any reports are found then it should send the notification if any reports are found.
<?php
namespace App\Console\Commands;
use Carbon\Carbon;
use App\Models\MerchantDeposit;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
class CheckCashIn extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'check:cashin';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Check expiration of cash in orders';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$setting = app(\App\Settings\CurrencySetting::class)->currency;
$expired_limit = app(\App\Settings\AdminSetting::class)->expired_payin_limit_notify;
$reports = [];
foreach ($setting as $currency => $s) {
$expired_minutes = $s['expired_minutes'];
$k = MerchantDeposit::where('status', MerchantDeposit::STATUS['PENDING'])
->where('currency', $currency)
->where('created_at', '<=', Carbon::now()->subMinutes($expired_minutes))
->update(['status' => MerchantDeposit::STATUS['EXPIRED']]);
$o = MerchantDeposit::where('merchant_deposits.status', MerchantDeposit::STATUS['EXPIRED'])
->join('reseller_bank_cards', 'reseller_bank_cards.id', 'merchant_deposits.reseller_bank_card_id')
->join('resellers', 'resellers.id', 'reseller_bank_cards.reseller_id')
->where('merchant_deposits.currency', $currency)
->where('merchant_deposits.created_at', '<=', Carbon::now()->subMinutes($expired_minutes))
->having(DB::raw('COUNT(resellers.name)'), '>=', $expired_limit)
->select('resellers.name', DB::raw('COUNT(resellers.name) AS total_expired'), DB::raw('TRUNCATE(SUM(merchant_deposits.amount), 2) AS total_amount'), 'merchant_deposits.currency')
->groupBy('resellers.name', 'merchant_deposits.currency')
->get();
if (!empty($o->toArray()) && $k > 0) {
$reports[$currency] = [];
foreach ($o as $k => $v) {
$reports[$currency][$v->name] = $v->total_expired;
$reports[$currency]['Total Amount'] = $v->total_amount;
}
}
}
if (!empty($reports)) {
Notification::send(\App\Models\Admin::all(), new \App\Notifications\DepositExpiredReport($reports));
}
}
}
And in Model/Admin.php i've set receivesBroadcastNotificationsOn to update the channel name for the broadcast to send into pusher.
<?php
namespace App\Models;
use App\Trait\HasJWTSubject;
use App\Trait\UserLogsActivity;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash;
use Illuminate\Notifications\Notifiable;
use Laravel\Lumen\Auth\Authorizable;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Spatie\Permission\Traits\HasRoles;
/**
* Model of admin
* #package Models
*/
class Admin extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
use Authenticatable, Authorizable, HasFactory, HasJWTSubject;
use UserLogsActivity;
use Notifiable;
use HasRoles;
protected $fillable = [
'name',
'username',
'password',
'status',
'timezone'
];
protected $hidden = [
'password',
];
protected $casts = [
'status' => 'boolean',
];
public const STATUS = [
'DISABLED' => false,
'ACTIVE' => true,
];
public function getIsSuperAdminAttribute()
{
return $this->hasRole('Super Admin');
}
public function setPasswordAttribute($value)
{
$this->attributes['password'] = Hash::needsRehash($value) ? Hash::make($value) : $value;
}
public function devices()
{
return $this->morphMany(Device::class, 'user');
}
public function receivesBroadcastNotificationsOn()
{
return 'App.Models.Admin.Notify';
}
}
When the notification is triggered from Notification::send(\App\Models\Admin::all(), new \App\Notifications\DepositExpiredReport($reports)); it will send broadcast notification multiple times to same broadcast channel as shown in the screenshot below
From Notification::send(\App\Models\Admin::all(), new \App\Notifications\DepositExpiredReport($reports)); it is fine to save the notification records for all the admin in database notification but for pusher i want the notification event to sent only once instead of sending multiple times ie 'x' number of admins.
Lets say i have 100 admin users then now pusher will send the event to same channel 100 times. So i want to minimize the pusher event to just 1 channel where all the admin users subscribed can receive the notification but it should also save the records for 100 users in the notification table of database.
I'm new at Laravel, and I'm trying to make Policies that will prevent user that doesn't have id_level 1 which is admin to access InventarisController, but the InventarisPolicy doesn't send variable to InventarisController.
it's my Inventaris Policies
InventarisPolicy.php
<?php
namespace App\Policies;
use App\{User, Level};
use Illuminate\Auth\Access\HandlesAuthorization;
class InventarisPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
public function inventaris_add(User $user)
{
$user->id_level == 1;
// dd($user);
// $user->id_level == 2;
}
}
it's my Inventaris Controller
InventarisController.php
<?php
namespace App\Http\Controllers;
use App\{Inventaris, DetailPinjamanView};
// use Illuminate\Http\Controllers\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
// use App\Http\Controllers\Auth\Request;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class InventarisController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
// $viewpinjaman = DetailPinjamanView::all();
$this->authorize('inventaris_add', $user);
$inventaris = Inventaris::all();
return view('index', compact('inventaris'));
}
I have this event to assign role:
<?php
namespace App\Listeners\User;
use App\Events\User\Created;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Http\Request;
use Spatie\Permission\Traits\HasRoles;
class AssignRoles
{
private $request;
/**
* Create the event listener.
*
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(Created $event)
{
$event->user;
dd($this->request->get('role'));
// here is the best place to do all the logic about roles that is going to be attached in this user. E.g:
switch($role = $this->request->input('role'))
{
case $role == 'Asesor':
$event->user->assignRole('Asesor');
break;
case $role == 'Comprador':
$event->user->assignRole('Comprador');
break;
default:
$event->user->assignRole('Writer');
}
}
}
but Laravarel doesn't return only "input role", returns always all params in request ¿why?
this is the print message with command dd:
"_token=7WvSpLbPgRrQ570hcXRnUZiGUOUroXiFLFih1dTa&role=Asesor"
I am trying to create multiple rows in the database table behind the scene in order to decrease page loading time so I am implementing laravel queue for that. But the actual job does not seem to be implementing without any errors
this is in my controller
public function store(SlotRequest $request)
{
$quota = 2;
$slotquota = request('slotamount') + $quota;
if ( auth()->user()->wallet->balance < $slotquota ) {
return Redirect::back()->with('low_balance', 'You do not have a sufficient wallet balance to reserve these SLOTS. Please Load Up Your Wallet');
} else {
// Getting SLOTS as objects of an array
$slotquantity = new SplFixedArray(request('slotamount'));
$slotquantity = $slotquantity->toArray();
$user = auth()->user();
SlotQueuer::dispatch($slotquantity, $user);
}
//Sorting Wallet Balance
$wallet = Wallet::where('user_id', auth()->user()->id)->first();
$wallet->balance = $wallet->balance - $slotquota;
$wallet->save();
//Returning View With Message
return Redirect::back()->with('reserved', 'Your SLOTS have been successfully reserved');
}
and for my job
namespace App\Jobs;
use App\Events\SlotCounter;
use App\Slot;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class SlotQueuer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $slotquantity;
protected $user;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(array $slotquantity, $user)
{
$this->slotquantity = $slotquantity;
$this->user = $user;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// Inserting Rows in SLOTS Table
foreach ($this->slotquantity as $slot) {
$slot = new Slot();
$slot->user_id = $this->user->id;
$slot->save();
//Slot Counting Event
event(new SlotCounter);
}
}
}
I am hoping to create database rows behind the scenes
Please change in your job class
protected $slotquantity;
protected $user;
public function __construct($slotquantity , $user)
{
$this->slotquantity = $slotquantity;
$this->user = $user;
}
In your handle() function
public function handle()
{
// Inserting Rows in SLOTS Table
foreach ($this->slotquantity as $slot) { //use this keyword to access slotquantity
$slot = new Slot();
$slot->user_id = $this->user->id;
$slot->save();
//Slot Counting Event
event(new SlotCounter);
}
}