Laravel 5 Command and Handler issue - laravel

I am working one of my project with laravel 5. During the implementation i got struct with one issue which is related to command and handler.
I used artisan command to generate command
php artisan make:command TestCommand --handler
I generated command at app/commands folder "TestCommand.php"
<?php
namespace App\Commands;
use App\Commands\Command;
class TestCommand extends Command
{
public $id;
public $name;
public function __construct($id, $name)
{
$this->id = $id;
$this->name = $name;
}
}
Also my TestCommandHandler.php looks like this
<?php
namespace App\Handlers\Commands;
use App\Commands\TestCommand;
use Illuminate\Queue\InteractsWithQueue;
class TestCommandHandler
{
/**
* Create the command handler.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the command.
*
* #param TestCommand $command
* #return void
*/
public function handle(TestCommand $command)
{
dd($command);
}
}
Whenever dispatch this command from controller it shows following issue
InvalidArgumentException in Dispatcher.php line 335:
No handler registered for command [App\Commands\TestCommand]
Please, Anybody help me to solve this problem. Thank you

By default Laravel 5.1.x does not included BusServiceProvider. So we should create BusServiceProvider.php under provider folder and include that in to config/app.php.
BusServiceProvider.php
<?php namespace App\Providers;
use Illuminate\Bus\Dispatcher;
use Illuminate\Support\ServiceProvider;
class BusServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #param \Illuminate\Bus\Dispatcher $dispatcher
* #return void
*/
public function boot(Dispatcher $dispatcher)
{
$dispatcher->mapUsing(function($command)
{
return Dispatcher::simpleMapping(
$command, 'App\Commands', 'App\Handlers\Commands'
);
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
config/app.php
'providers' => [
App\Providers\BusServiceProvider::class
]
So it may help others. Thank you

Related

Call to a member function expectsOutput() on integer when testing artisan console command

I have a very simple example to show the problem:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class VendorCounts extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'vendor:counts
{year : The year of vendor counts}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Runs vendor counts';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->info('Starting Vendor Counts');
}
}
<?php
namespace Tests\Feature\Console\Vendor;
use Tests\TestCase;
class VendorCountsTest extends TestCase {
public function testVendorCounts()
{
$this->artisan('vendor:counts', ['year' => 2019])
->expectsOutput('Starting Vendor Counts')
->assertExitCode(0);
}
}
I get the following error:
1) Tests\Feature\Console\Vendor\VendorCountsTest::testVendorCounts
Error: Call to a member function expectsOutput() on integer
/Users/albertski/Sites/vrs/tests/Feature/Console/Vendor/VendorCountsTest.php:12
I know the command definitely runs because if I put a dump statement in it shows the debug output.
I am using Laravel 6.3. Is there a different way to test this?
The problem I was using was that TestCase was using Laravel\BrowserKitTesting\TestCase as BaseTestCase. I ended up creating another Base just for console commands.
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class ConsoleTestCase extends BaseTestCase
{
use CreatesApplication;
}
Can you add this to your VendorCountsTest class:
public $mockConsoleOutput = true;
This is set by a trait but just making sure something hasn't changed the value. When $mockConsoleOutput is false it will directly run the artisan commmand. When it is true it will wrap it in a PendingCommand object that has those methods you are trying to call.
I had an issue where the use of expectedOutput() on my Artisan class would fail all the time, which turned out to be because I had used exit() and/or die() in a method, which really did not work well with phpunit test methods.
So if you want to stop processing the "script" at some point, just use an empty return and not exit() or die() if you want to utilize the built-in ->artisan() testing in Laravel.
Working example:
<?php
// app/Console/Commands/FooCommand.php
public function handle()
{
$file = $this->argument('file');
if (! file_exists($file)) {
$this->line('Error! File does not exist!');
return;
}
}
// tests/Feature/FooCommandTest.php
public function testFoo() {
$this->artisan('foo', ['file' => 'foo.txt'])->expectsOutput('Something');
}
Non-working example:
<?php
// app/Console/Commands/FooCommand.php
public function handle()
{
$file = $this->argument('file');
if (! file_exists($file)) {
$this->line('Error! File does not exist!');
exit;
}
}
// tests/Feature/FooCommandTest.php
public function testFoo() {
$this->artisan('foo', ['file' => 'foo.txt'])->expectsOutput('Something');
}

Laravel Nova - Change Tool to Resource Tool

I'm trying to convert a build Nova tool to a resource tool. I've tried to change my Tool to extend ResourceTool instead of Tool and add the resource tool to the Resource in the fields, but it's not showing up. I also changed the code of ToolServiceProvider to match that of a ResourceTool but it does not work unfortunately.
I've searched the internet but I seem to be the only one having this issue, anyone ever experienced this and know what to do? I'm not getting any error message, the resource tool just is not showing up.
Here is my code, I removed some of it for readability and confidentiality.
Product (Resource)
<?php
namespace App\Nova;
use confidentiality\SalesHistory\SalesHistory;
class Product extends Resource
{
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
SalesHistory::make(),
];
}
}
SalesHistory (Resource tool)
<?php
namespace confidentiality\SalesHistory;
use Laravel\Nova\ResourceTool;
class SalesHistory extends ResourceTool
{
/**
* Get the displayable name of the resource tool.
*
* #return string
*/
public function name()
{
return 'Sales History';
}
/**
* Get the component name for the resource tool.
*
* #return string
*/
public function component()
{
return 'sales-history';
}
}
ToolServiceProvider (Resource Tool)
<?php
namespace confidentiality\SalesHistory;
use Laravel\Nova\Nova;
use Laravel\Nova\Events\ServingNova;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
class ToolServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$this->app->booted(function () {
$this->routes();
});
Nova::serving(function (ServingNova $event) {
Nova::script('sales-history', __DIR__.'/../dist/js/tool.js');
Nova::style('sales-history', __DIR__.'/../dist/css/tool.css');
});
}
/**
* Register the tool's routes.
*
* #return void
*/
protected function routes()
{
if ($this->app->routesAreCached()) {
return;
}
Route::middleware(['nova'])
->prefix('nova-vendor/sales-history')
->group(__DIR__.'/../routes/api.php');
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
I managed to fix it finally. I also had to change the tool.js file to match that of a Resource Tool.
Nova.booting((Vue, router, store) => {
Vue.component('sales-history', require('./components/Tool'))
})
Try this command from the root of project: composer update

Display counter variable in my layout.app.blade in Laravel

i want to display the counter in my app.blade which being called in all pages like the screenshot below
I only have this function in my controller
class ReportsController extends Controller
{
public function invoiceTransaction()
{
$salespayments = Salespayments::where('type','=','check')->get();
$countUnread = Salespayments::select(DB::raw("SUM(unread) as unread"))->get();
return view('reports.invoiceTransactions')
->with('salespayments', $salespayments)
->with('countUnread', $countUnread);
}
}
And I am calling the counter in my blade by this {{$countUnread[0]->unread}}
How can I make that function be readable in my app.blade.php? thanks a lot!
In your AppServiceProvider you can share the sum result across all views by using view()->share();
Like this:
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
$countUnread = Salespayments::sum('unread');
view()->share('countUnread', $countUnread);
}
Make a service provider first,
php artisan make:provider CounterServiceProvider
Then in your CounterServiceProvider file.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Views\Composers;
class CounterServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
// here define your master layout
$this->app['view']->composer(['master'], Composers\Counter::class);
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
Now in your App\Views\Composers folder add Counter class.
<?php
namespace App\Views\Composers;
use Illuminate\View\View;
class Counter {
public function compose(View $view)
{
$view->with('countUnread', session('countUnread'));
}
}
Make sure you add your CounterServiceProvider in config/app.php file's providers array.

How to properly add external php files in Laravel 5

I have a small websockets chat written, the php part is just 2 files, server.php and Chat.php, they are both inside a bin folder and depend on ratchet and some other libraries which I downloaded to the laravel installation via composer.
server.php
require __DIR__.'/../vendor/autoload.php';
require 'Chat.php';
use Ratchet\Server\IoServer;
use Ratchet\http\HttpServer;
use Ratchet\WebSocket\WsServer;
$server = IoServer::factory(new HttpServer(new WsServer(new Chat)), 8080);
$server->run();
Chat.php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
foreach ($this->clients as $client)
{
if ($client !== $conn ) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo 'the following error occured: ' . $e->getMessage();
$conn->close();
}
}
Now, I have that bin folder inside the laravel root, and so I am able to start the server since the server.php is looking for dependencies in vendor one level up, but what I wanna do is use all the laravel goodies within these files, especially within Chat.php.
So now for example if I write use DB in Chat.php it gives an error (which I understand, it has no way of knowing laravel), so my question is how do I include this bin folder and its files so that I can use all the laravel goodies within them?
You do not need to manually load vendor/autoload.php because laravel does that for you.
First you have to create folder inside your YourLaravelRoot/app dir(Let's name that as Services). Then move chat.php into that, rename it to ChatService.php(Change class name also to ChatService) or any appropriate name(reccomanded to ends with xxxxService so it's easier to identify) and namespace it as namespace App\Services;(Assumming that your app name is App).Namespacing correctly is important otherwise you have to manually loads it throught composer.json .Then create a artisan command and move content of server.php into handle method inside command(Let's name it ServerCommand.php). Add use App\Services\ChatService as Chat;. Register the command in Kernal.php on app/console That's it. Now you should be able to access any laravel facade inside ChatService
Summary:
YourLaravelProject
-app
--Console
Kernal.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
Commands\ServerCommand::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
}
}
---Commands
----ServerCommand.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use App\Services\ChatService as Chat;
class ServerCommand extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'server:run';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$server = IoServer::factory(new HttpServer(new WsServer(new Chat)), 8080);
$server->run();
}
}
--Services
---ChatService.php
<?php
namespace App\Services;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
/**
*
*/
class ChatService implements MessageComponentInterface {
{
protected $clients;
function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
}
public function onMessage(ConnectionInterface $conn, $msg)
{
foreach ($this->clients as $client)
{
if ($client !== $conn ) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo 'the following error occured: ' . $e->getMessage();
$conn->close();
}
}
Execute command php artisan server:run

Laravel 5.2 RethinkDB Service Provider Preventing Creation of Migration Files

I followed the installation to install this service provider, but each time I try to create a migration file I get this error:
[ErrorException]
Argument 2 passed to duxet\Rethinkdb\Console\Migrations\MigrateMakeCommand::__construct() must be an instance
of Illuminate\Foundation\Composer, instance of Illuminate\Support\Composer given, called in D:\projects\app\vendor\duxet\laravel-rethinkdb\src\RethinkdbServiceProvider.php on line 41 and defined
I'm on line 41 and can see that the second parameter is $composer, which equals $composer = $app['composer'];. I thought maybe changing Illuminate\Support\Composer to Illuminate\Foundation\ServiceProvider might just fix the issue, but doing this throws another error saying that:
[Symfony\Component\Debug\Exception\FatalErrorException]
Class 'Illuminate\Foundation\ServiceProvider' not found
Anyone running into this issue?
Update
Where the original error is occurring (I marked Line 41):
<?php
namespace duxet\Rethinkdb;
use duxet\Rethinkdb\Console\Migrations\MigrateMakeCommand;
use duxet\Rethinkdb\Eloquent\Model;
use duxet\Rethinkdb\Migrations\MigrationCreator;
use Illuminate\Support\ServiceProvider;
class RethinkdbServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot()
{
Model::setConnectionResolver($this->app['db']);
Model::setEventDispatcher($this->app['events']);
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->resolving('db', function ($db) {
$db->extend('rethinkdb', function ($config) {
return new Connection($config);
});
});
$this->app->singleton('command.rethink-migrate.make', function ($app) {
$creator = new MigrationCreator($app['files']);
$composer = $app['composer'];
return new MigrateMakeCommand($creator, $composer); <= line 41
});
$this->commands('command.rethink-migrate.make');
}
public function provides()
{
return ['command.rethink-migrate.make'];
}
}
The MigrateMakeCommand class:
<?php
namespace duxet\Rethinkdb\Console\Migrations;
use duxet\Rethinkdb\Migrations\MigrationCreator;
use Illuminate\Database\Console\Migrations\MigrateMakeCommand as LaravelMigration;
use Illuminate\Foundation\Composer;
class MigrateMakeCommand extends LaravelMigration
{
/**
* The console command signature.
*
* #var string
*/
protected $signature = 'make:rethink-migration {name : The name of the migration.}
{--create= : The table to be created.}
{--table= : The table to migrate.}
{--path= : The location where the migration file should be created.}';
/**
* Create a new migration install command instance.
*
* #param duxet\Rethinkdb\Migrations\MigrationCreator $creator
* #param \Illuminate\Foundation\Composer $composer
*
* #return void
*/
public function __construct(MigrationCreator $creator, Composer $composer)
{
parent::__construct($creator, $composer);
}
}

Resources