How can I call command schedule via url on the laravel? - laravel

I using laravel 5.6
I set my schedule in the kernel.php like this :
<?php
namespace App\Console;
use App\Console\Commands\ImportLocation;
use App\Console\Commands\ImportItem;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
ImportLocation::class,
ImportItem::class,
];
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')->dailyAt('23:00');
}
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
So there are two command
I will show one of my commands like this :
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Location;
class ImportLocation extends Command
{
protected $signature = 'import:location';
protected $description = 'import data';
public function __construct()
{
parent::__construct();
}
public function handle()
{
...
}
}
I want to run the command via url. So it not run in the command promp
I try like this :
I add this script : Route::get('artisan/{command}/{param}', 'CommandController#show');
in the routes and I make a controller like this :
namespace App\Http\Controllers;
class CommandController extends Controller
{
public function show($command, $param)
{
$artisan = \Artisan::call($command.":".$param);
$output = \Artisan::output();
return $output;
}
}
And I call from url like this : http://myapp-local.test/artisan/import/location
It works. But it just run one command
I want to run all command in the kernel. So run import location and import item
How can I do it?

What you can do is register a custom method in your Kernel.php to retrieve all custom registered commands in the protected $commands array:
public function getCustomCommands()
{
return $this->commands;
}
Then in your controller you can loop them all and execute them via Artisan's call() or queue() methods:
$customCommands = resolve(Illuminate\Contracts\Console\Kernel::class)->getCustomCommands();
foreach($customCommands as $commandClass)
{
$exitCode = \Artisan::call($commandClass);
//do your stuff further
}
More on Commands you can understand on the documentation's page

Related

getJson in test in laravel does not get passed to controller

I have a test in a Laravel project where I do a getJson request and some answer should be returned. But the method in the controller doesn't get hit.
The test
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Notifications\DatabaseNotification;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class NotificationsTest extends TestCase
{
use DatabaseMigrations;
public function setUp(): void
{
parent::setUp();
$this->signIn();
}
public function test_a_user_can_fetch_their_unread_notifications()
{
create(DatabaseNotification::class);
$response = $this->getJson(url('/profiles') . '/' . auth()->user()->name . '/notifications')->json();
$this->assertCount(1, $response);
}
The line in webp.php that should process this request:
Route::get('/profiles/{user}/notifications', 'UserNotificationsController#index');
The UserNotificationsController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\User;
class UserNotificationsController extends Controller
{
public function __construct()
{
$this->middelware('auth');
}
public function index() {
dd(" UsderNotificationsController-Index method hit");
return auth()->user()->unreadNotifications;
}
public function destroy(User $user, $notificationId)
{
dd(' Destroy method hit');
auth()->user()->notifications()->findOrFail($notificationId)->markAsRead();
}
}
If I run the test with phpunit, I would expect that the DD() in the index method should be executed. But it doesn't.
I tried all kinds of variations to generate the URI, but always get the same result. Can anyone tell me why I do not generate the correct URI?
Kind regards,
HUbert
//start by doing that : in your controller
Route::get('/profiles/notifications', 'UserNotificationsController#index');
public function test_a_user_can_fetch_their_unread_notifications()
{
$this->withoutHandlingException();
create(DatabaseNotification::class,['user_id'=>$this->signIn()->id]);
$this->signIn()//i think it should return authenticated user
$response = $this->get('/profiles/notifications')
->assertStatus(200);
// $this->assertCount(1, $response);
}
-//in your index function
public function index() {
dd(" UsderNotificationsController-Index method hit");
return response()->json(auth()->user()->unreadNotifications,200);
}

Generate files using custom artisan make command Laravel

I am trying to generate a class file using custom artisan make command.My command is showing under artisan make but I am not able to generate file
What i did
1.Use php artisan make:command CreateActionClass and implement GeneratorCommand
<?php
namespace App\Console\Commands;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Input\InputArgument;
class CreateActionClass extends GeneratorCommand
{
protected $signature = 'make:action {name}';
protected $description = 'Create New Action Single Responsibility';
protected $type = 'Action';
public function handle()
{
//
}
protected function getStub()
{
return app_path().'/Console/Stubs/MakeActionStub.stub';
}
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Actions';
}
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the contract.'],
];
}}
2. Generate .stub file /Console/Stubs/MakeActionStub.stub
<?php
namespace DummyNamespace;
class DummyAction
{
}
Please Help
Remove the handle method. It is overriding the GeneratorCommand class's handle that's why its doing nothing. If you wish to extend the handle method, call parent::handle() before or after your statements

How to implement event/listeners with repository pattern in laravel 5.4

I can't make listeners trigger action update, create or delete when I user patter repository.
Addionally I have added my code in order to help my to solve my problem.
TicketController.php
namespace App\Http\Organizer\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Events\Contracts\IEvent;
use App\Entities\Event;
class TicketController extends Controller
{
protected $IEvent;
public function __construct( IEvent $IEvent )
{
$this->IEvent = $IEvent;
}
public function checkFutbolType ($activityId)
{
// I need to listen this action here
$event = $this->IEvent->update(21927, ['title'=>'new title']);
}
}
My RepoEvent.php:
<?php
namespace App\Http\Events\Repositories;
use App\Http\Events\Contracts\IEvent
;
class RepoEvent implements IEvent
{
protected $model;
public function __construct($model)
{
$this->model = $model;
}
public function update($activityId, $params)
{
return $this->model->where('id', $activityId)->update($params);
}
}
My AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Entities\Event;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//event: creating
Event::creating(function (Event $event) {
return $event->creatingEvent();
});
//event: saving
Event::saving(function (Event $event) {
return $event->savingEvent();
});
//event: updating
Event::updating(function (Event $event) {
return $event->updatingEvent();
});
}
}
My interface IEvent.php:
<?php
namespace App\Http\Events\Contracts;
interface IEvent
{
public function update($activityId, $params);
}
My ServicesOrchestration.php:
<?php
namespace App\Http\Administration\Providers;
use App\Entities\Event;
use App\Http\Administration\Repositories\RepoEvent;
use Illuminate\Support\ServiceProvider;
class ServicesOrchestration extends ServiceProvider
{
public function boot()
{
}
public function register()
{
$this->app->bind('App\Http\Administration\Contracts\IEvent', function () {
return new RepoEvent(new Event());
});
}
}
My model Event.php
<?php
namespace App\Entities;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
public function creatingUser() {
\Log::info('creating event');
}
public function savingUser() {
\Log::info('saving event');
}
public function updatingUser() {
\Log::info('updating event');
}
}
thanks in advance.thanks in advance.thanks in advance.thanks in advance.thanks in advance.thanks in advance
Here's the relevant snipped from the docs (scroll to mass updates):
When issuing a mass update via Eloquent, the saved and updated model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.
For your code to work you need to first retrieve the actual model instance like below:
public function update($activityId, $params)
{
$instance = $this->model->find($activityId);
$instance->fill($params);
$instance->save();
}
This will have an additional cost of doing two queries instead of one and only being able to update a single model at a time.
A sidenote: You're passing a model instance to the repository but what you actually want is to pass a query builder instance:
$this->app->bind('App\Http\Administration\Contracts\IEvent', function () {
return new RepoEvent(Event::query());
});

Laravel and Local Tunnel integration

My idea was to use Local Tunnel's subdomain feature to expose callback URI in a more convenient way. However, I believe that I could've achieved the same results in a simper way.
This is the solution with Laravel Valet:
In package.json I've added a script called shared
"scripts": {
...
"share": "lt --port 80 --subdomain blog --local-host blog.test"
}
In AppServiceProvider.php I've extended the UrlGenerator to avoid redirecting back to http://blog.test
<?php
namespace App\Providers;
use App\Services\LocalTunnelUrlGenerator;
use Blade;
use Illuminate\Http\Resources\Json\Resource;
use Illuminate\Routing\Router;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
(...)
}
public function register()
{
$this->enableLocalTunnel();
}
private function enableLocalTunnel()
{
if (!app()->environment('local') || !config('app.use_local_tunnel')) {
return;
}
$this->app->extend('url', function (UrlGenerator $defaultGenerator) {
/** #var Router $router */
$router = $this->app['router'];
$routes = $router->getRoutes();
return new LocalTunnelUrlGenerator($routes, $defaultGenerator->getRequest());
});
}
}
This is the the LocalTunnelUrlGenerator.php:
<?php
namespace App\Services;
use Illuminate\Http\Request;
use Illuminate\Routing\RouteCollection;
use Illuminate\Routing\UrlGenerator;
class LocalTunnelUrlGenerator extends UrlGenerator
{
public function __construct(RouteCollection $routes, Request $request)
{
parent::__construct($routes, $request);
}
public function formatRoot($scheme, $root = null)
{
return "https://blog.localtunnel.me";
}
}
Why all that? Because whenever the application call the redirect() method, we are sent back to http://blog.test.
Do I really need to extend the UrlGenerator to make it work?

call a model from a command class in Laravel 5, and pass the command class itself

I have a laravel 5.5 artisan command working, so of course I can use methods like $this->info() and $this->arguments() etc.. it looks like this:
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Config;
use Compasspointmedia\Julietmenu\Model\Menu;
class MenuManagementCommand extends Command
{
/**
* The console command name.
*
* #var string
*/
protected $signature = 'julietmenu:menu
{action=list}';
protected $description = 'Manages menu elements per the Juliet CMS specification';
public function __construct() {
parent::__construct();
//trying to make this command methods available in Menu
$this->menu = new Menu($this);
}
/**
* Execute the console command.
*/
public function handle()
{
// this works just fine
$this->info('Calling ' . $this->argument('action'));
$action = $this->argument('action');
$this->menu->action();
}
}
Of course, I would like do the actual work in the Model, not the command, using the command like a controller. Here's the model class so far:
namespace Compasspointmedia\Julietmenu\Model;
use Illuminate\Database\Eloquent\Model;
class Menu extends Model {
//
public function __construct($command){
$this->command = $command;
// this says the `arguments` method is present:
print_r(get_class_methods($this->command));
// but, it does not work!
// error: "Call to a member function getArguments() on null"
$this->arguments = $this->command->arguments();
}
public function node(){
echo '--- it works! -----';
}
}
To the point, how do I pass the Command object to the Model so that I can use $this->command->arguments() or the other Command features inside the model?
P.S. I'd be very grateful to know if there's a native "Laravel way" to do this better than passing the entire $this to a constructor.

Resources