Laravel 4 artisan command not seeing binding - laravel-4

I created a command called AttachUsers. When I run the command I get
Argument 1 passed to AttachPhones::__construct() must be an instance of Acme\\Repositories\\Organizations\\OrganizationRepositoryInterface, none given, called in \/Users\/jonson\/sites\/acme\/app\/start\/artisan.php on line 5 and defined","file":"\/Users\/jonson\/sites\/acme\/app\/commands\/AttachPhones.php","line":30}}
I have bound my interface in the repositories service provider file AND it is currently woking in my controllers. My command file is as follows
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use \Acme\Repositories\Organizations\OrganizationRepositoryInterface;
class AttachUsers extends Command {
protected $organizations;
/**
* The console command name.
*
* #var string
*/
protected $name = 'acme:attach_users';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Cron command to attach users from import to organizations';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct(OrganizationRepositoryInterface $organizations)
{
$this->organizations = $organizations;
parent::__construct();
}

You're probably calling Artisan::add(new MyCommand). Any time you use the "new" keyword, the IoC container is completely bypassed, and automatic dependency injection will not work. Instead, use Artisan::add(App::make('MyCommand')) or the shorthand, Artisan::resolve('MyCommand').

Related

Laravel command with option (without value) is not defined

Hi I have a weird issue with passing an option to a command from another command.
Command A
protected $signature = 'foo:bar {--internal}';
Command B
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class FooBaz extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'foo:baz';
/**
* The console command description.
*
* #var string
*/
protected $description = '';
/**
* Execute the console command.
*
* #return int
*/
public function handle()
{
$this->call('foo:bar --internal');
}
}
Calling foo:baz yields
Command "foo:bar --internal" is not defined.
While calling foo:baz --internal just works. Is this a bug?
According to the documentation, the options can be passed as an arguments
Example:
$this->call('foo:bar', ['internal']);

Run external command via Laravel Artisan Console

I'm looking to execute psexec from Laravel to execute some remote command and I'd like to use the Artisan Console to do so (for now). Ideally, I'd like to navigate to a url and the command would be issued (something i'd implement after this initial stage).
What I have so far is:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class RestartSplunk extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'splunk:restart {host}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Restart Splunk instance on given host';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$host = $this->argument('host');
$bar = $this->output->createProgressBar();
if ($this->confirm('Are you sure you\'d like to restart ' . $host )) {
$this->info('Restarting ' . $host . '...');
}
}
}
If someone has implemented this or can share some resources to accomplish this it'd me much appreciated.
I have found my answer The Process Component in Symphony.

Custom laravel migration command "[Illuminate\Database\Migrations\MigrationRepositoryInterface] is not instantiable"

I'm trying to create a custom laravel (5.2) migration command that basically works the same as migrate:status except it just lists the pending migrations instead of all the migrations.
To do this i've very simply copied the migrate:status into another class within my app/console directory and adjusted the code to suit my needs. However whenever I try to run it I get an error:
[Illuminate\Contracts\Container\BindingResolutionException]
Target [Illuminate\Database\Migrations\MigrationRepositoryInterface] is not instantiable while building [App\Console\Commands\PendingMigrations, Illuminate\Database\Migrations\Migrator].
The contents of the class itself and the fire() method doesn't seem to matter as it doesn't get that far, it fails within the __construct() method.
<?php namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Database\Migrations\Migrator;
class PendingMigrations extends Command
{
/**
* The console command name.
*
* #var string
*/
protected $name = 'migrate:pending';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Shows a list of pending migrations';
/**
* The migrator instance.
*
* #var \Illuminate\Database\Migrations\Migrator
*/
protected $migrator;
/**
* Create a new migration rollback command instance.
*
* #param \Illuminate\Database\Migrations\Migrator $migrator
* #return \Illuminate\Database\Console\Migrations\StatusCommand
*/
public function __construct(Migrator $migrator)
{
parent::__construct();
$this->migrator = $migrator;
}
/**
* Execute the console command.
*
* #return void
*/
public function fire()
{
}
}
The reason for it is likely to be something to do with the IoC container and the order with which things are loaded, but I don't know enough about the inner workings of Laravel to figure out any more than that.
It surely must be possible?
I am currently stuck on 5.2, so i'm not sure if this problem exists in more recent versions.
The only thing i've attempted so far is added the migration service provider to the top of the list in config/app.php however it didn't seem to have an affect and it was just a random guess anyway.
providers' => [
Illuminate\Database\MigrationServiceProvider::class,`
]
I got around this using:
$this->migrator = app('migrator');
but it is not necessarily the best way to do this
The Migrator instance is not bound to the class name in the IoC container, it is bound to the migrator alias.
From Illuminate\Database\MigrationServiceProvider:
/**
* Register the migrator service.
*
* #return void
*/
protected function registerMigrator()
{
// The migrator is responsible for actually running and rollback the migration
// files in the application. We'll pass in our database connection resolver
// so the migrator can resolve any of these connections when it needs to.
$this->app->singleton('migrator', function ($app) {
$repository = $app['migration.repository'];
return new Migrator($repository, $app['db'], $app['files']);
});
}
Since the class name is not bound in the IoC container, when Laravel resolves your command and attempts to resolve the Migrator dependency, it attempts to build a new one from scratch and fails because the Illuminate\Database\Migrations\MigrationRepositoryInterface is also not bound in the IoC container (hence the error you're receiving).
Since Laravel can't figure this out itself, you need to either register the binding for the Migrator class name, or you need to register the binding for your command. Laravel itself registers all the bindings for the commands in the Illuminate\Foundation\Providers\ArtisanServiceProvider. An example of the command.migrate binding:
/**
* Register the command.
*
* #return void
*/
protected function registerMigrateCommand()
{
$this->app->singleton('command.migrate', function ($app) {
return new MigrateCommand($app['migrator']);
});
}
So, in your AppServiceProvider, or another service provider you setup, you can add one of the following:
Register the command in the IoC:
$this->app->singleton(\App\Console\Commands\PendingMigrations::class, function ($app) {
return new \App\Console\Commands\PendingMigrations($app['migrator']);
});
Or, register the Migrator class name in the IoC:
$this->app->singleton(\Illuminate\Database\Migrations\Migrator::class, function ($app) {
return $app['migrator'];
});
As I don't want to register the migrator everywhere in the app, but I still want to extend the MigrateCommand itself, I came up with this approach to maintain my app as it is:
public function __construct()
{
app()->singleton(\App\Console\Commands\PendingMigrations::class, function ($app) {
return new \App\Console\Commands\PendingMigrations($app['migrator']);
});
parent::__construct(app('migrator'));
}

Pass object to task scheduler

I'm using Laravel 5.2's task scheduler. I need to be able to pass two options to the scheduler, but I'm not sure how to do this.
Here is what I have in my Kernel.php:
protected function schedule(Schedule $schedule)
{
$schedule->command('simple_cron --first_option=10')
->everyMinute();
}
And this in my simple_cron command:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Article;
class SimpleCron extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'simple_cron';
/**
* The console command description.
*
* #var string
*/
protected $description = '';
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$firstOption = $this->option('first_option');
}
}
But this gives me the error:
The "--first_option" option does not exist.
What am I doing wrong?
According to the offical documentation the first thing is that your signature needs to have one/two placeholders for parameters:
protected $signature = 'simple_cron {p1} {p2} {--firstoption=5}';
Here we set a default value of 5 for the option firstoption. If you don't want a default value just write {--firstoption=}
To fetch those parameters in your handle method you can do it like that:
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$p1 = $this->argument('p1'); // should be 10
$p2 = $this->argument('p2'); // should be 20
$option1 = $this->option('firstoption'); // should be 99
//
}
You should then be able to call it like this:
$schedule->command('simple_cron 10 20 --firstoption=99')->daily();

Creating a new Command using Artisan, without shell access

I need to set some cron jobs on a Laravel website. It seems that first I have to run the following command in the shell to begin with it:
php artisan command:make CustomCommand
However since I don't have shell access, my only other option is to use Artisan::call and access is it over HTTP. The syntax is something like this:
\Artisan::call( 'command:make',
array(
'arg-name' => 'CustomCommand',
'--option' => ''
)
);
The problem that I'm facing is that I can't seem to find the arg-name value for the command:make command.
I really appreciate if someone mention the Argument Name for the make command or suggest an alternative solution that doesn't need shell access.
You can add this manually by creating a class that represents your command. The cli command generates next file :
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class Test extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'command:name';
/**
* 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 fire()
{
//
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array(
array('example', InputArgument::REQUIRED, 'An example argument.'),
);
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array(
array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}
put it in your commands directory (for L4 it's app/commands). Next simply add to your app/start/artisan.php file the binding for your custom command :
Artisan::add(new Test);
and that's it. This is the ideal solution when you don't need to touch your server's crontab. In case you have access to it from CP it would be the simplest solution. In case you don't have such ability, there would be now way to set the crontab to run your custom command. Hope this helps.

Resources