Consider the following task:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Foundation\Inspiring;
use App\Etis\Domain\Services\TwitterService;
use \Twitter;
use Log;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
class FetchTweets extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'fetch_tweets';
/**
* The console command description.
*
* #var string
*/
protected $description = 'fetches the latest ten tweets';
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$logInstance = Log::getMonolog();
$logInstance->pushHandler(new StreamHandler(storage_path('logs/tweets.log'), Logger::INFO));
$tweets = Twitter::getUserTimeline([
'screen_name' => env('TWITTER_USER_NAME'),
'count' => env('TWITTER_TWEET_AMOUNT'),
'format' => 'json'
]);
$logInstance->addInfo('Tweets', [$tweets]);
$twitterService = new TwitterService();
$twitterService->processTweets(json_decode($tweets, true));
}
}
Which is then set up as such:
$schedule->command('fetch_tweets')
->everyMinute()
->withoutOverlapping()
->appendOutputTo('storage/logs/tweets.log');
When I look, on production and even in local, I see that both the laravel.log and the tweets.log file have the contents that I printing out to tweets.log.
Why is this? How do I make it ONLY print out to tweets.log?
pushHandler() does not replace existing log handler. Instead, it adds a new log handler to the existing, predefined list of handlers. That's the reason why you're now getting your message logged in 2 log files now.
You need to call setHandlers() to overwrite the list of handlers:
$handler = new StreamHandler(storage_path('logs/tweets.log'), Logger::INFO);
$logInstance = Log::getMonolog();
$logInstance->setHandlers(array($handler));
Related
I need to run one of my Laravel Dusk tests from an artisan command so that it processes daily. I've tried $this->call('dusk'); in my command but that runs all of dusk's tests and doesn't allow me to add a group or a filter. I need to run just 1 test. How can I add a filter?
$this->call('dusk', [ '--group' => 'communication_tests' ]);
or
$this->call('dusk', [ '--filter' => 'tests\Browser\myTestFile::myTestMethod' ]);
doesn't work and it ignores the options passed in. Any ideas on how to accomplish this?
1st create your working Laravel Dusk Test. Test it out with php artisan dusk and make sure it's working.
2nd create your own command in the app\Commands folder called DuskCommand to overwrite laravels native DuskCommand and have it's signature be 'dusk'. Have it extend Laravel\Dusk\Console\DuskCommand and write into its handle method the code below (see https://github.com/laravel/dusk/issues/371 for other version of this code). I edited mine to remove the $this->option('without-tty') ? 3 : 2 ternary statement so it just reads 2 for mine as that option didn't exist or wasn't needed for my version of laravel.
3rd add your new class to the Kernel so that when you call php artisan dusk the class is recognized.
4th create your new command to programmatically run your dusk test using the final line added by #taytus.
5th add that new class to the Kernel also.
Here's my file run down below...
My laravel dusk test (tests\Browser\CommunicationsTest.php) (STEP 1)
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use App\Models\User;
class CommunicationsTest extends DuskTestCase
{
/**
* A Dusk test example.
* #group all_communication_tests
* #return void
*/
public function test_that_all_coms_work()
{
// Test Text
$this->browse(function (Browser $browser) {
$browser->resize(1920, 1080);
$browser->loginAs(7)
->visit('/events/types/appointments')
->assertSee('Automated Messages')
->click('.text_message0')
->pause(1000)
->click('.send-eng-text-btn')
->pause(1000)
->type('phone', env('TESTING_DEVELOPER_PHONE'))
->click('.send-text')
->pause(5000)
->assertSee('Your test text has been sent.');
// Test Email
$browser->visit('/events/types/appointments')
->assertSee('Automated Messages')
->click('.email0')
->assertSee('Automated Messages')
->driver->executeScript('window.scrollTo(595, 1063);');
$browser->click('.send-eng-email-btn')
->pause(2000)
->click('.send-email')
->pause(10000)
->assertSee('Your test email has been sent.');
// Test Call
$browser->visit('/audio/testcall')
->assertSee('Test Call')
->type('phone', env('TESTING_DEVELOPER_PHONE'))
->press('Call')
->pause(3000)
->assertSee('Test Call Queued');
});
}
}
My Overwritting dusk command (app\Console\Commands\DuskCommand.php) (STEP 2)
<?php
namespace App\Console\Commands;
use Laravel\Dusk\Console\DuskCommand as VendorDuskCommand;
use Symfony\Component\Process\ProcessBuilder;
class DuskCommand extends VendorDuskCommand
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'dusk';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Run Tests on our system... by extending the Laravel Vendor DuskCommand.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->purgeScreenshots();
$this->purgeConsoleLogs();
$options=array();
// This line checks if it is a direct call or if has been called from Artisan (we assume is Artisan, more checks can be added)
if($_SERVER['argv'][1]!='dusk'){
$filter=$this->input->getParameterOption('--filter');
// $filter returns 0 if has not been set up
if($filter){
$options[]='--filter';
$options[]=$filter;
// note: --path is a custom key, check how I use it in Commands\CommunicationsTest.php
$options[]=$this->input->getParameterOption('--path');
}
}else{
$options = array_slice($_SERVER['argv'], 2);
}
return $this->withDuskEnvironment(function () use ($options) {
$process = (new ProcessBuilder())
->setTimeout(null)
->setPrefix($this->binary())
->setArguments($this->phpunitArguments($options))
->getProcess();
try {
$process->setTty(true);
} catch (RuntimeException $e) {
$this->output->writeln('Warning: '.$e->getMessage());
}
return $process->run(function ($type, $line) {
$this->output->write($line);
});
});
}
}
Now add that new command to the Kernel so it will register when you call it and overwrite the functionality of the native/vendor DuskCommand. (STEP 3)
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
// .... preceding commands....
Commands\DuskCommand::class,
];
Now create your command that will call dusk programmatically - here's mine (STEP 4)
<?php
namespace App\Console\Commands;
use DB;
use Illuminate\Console\Command;
class TestCommunications extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'test:communications';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Test Email, Text, and Phone Calls to make sure they\'re operational.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$response = $this->call('dusk',['--filter'=>'test_that_all_coms_work','--path'=>'tests/Browser/CommunicationsTest.php']);
}
}
and register it in the Kernel (STEP 5)...
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
.... preceding commands....
Commands\DuskCommand::class,
Commands\TestCommunications::class,
];
Now run php artisan dusk and it should hit the extending DuskCommand and work fine. Then call your new php artisan command that replaces my TestCommunications.php file and it should run dusk perfectly... assuming your test works of course. Let me know if you have any question or if I left anything out.
Remember Dusk only works in a local environment ... this is not something you want/should/natively can implement on a production environment
I'm trying to send an email using a command in Laravel. I would like to send a file from a specific folder. Previously I did it using a view with a form, but now I want to send the email using a command. The file will always be in the same folder.
This is the command code:
<?php
namespace efsystem\Console\Commands;
use Illuminate\Console\Command;
use Storage;
use Mail;
use Config;
class SendEmailEfsystem extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'emails:send';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Sending emails to the users';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$data = array(
'destino' => 'example#gmail.com',
'asunto' => 'example',
);
Mail::send('administracion.email.email_body', $data, function ($message) use ($data) {
$message->to($data['destino']);
$message->subject($data['asunto']);
$message->from(Config::get('mail.username'));
});
$this->info('The emails are send successfully!');
}
}
Since in the "form" you used $request['a_file'] the variable was an instance of Symfony\Component\HttpFoundation\File\UploadedFile wich is an extention of Symfony\Component\HttpFoundation\File\File.
what you need to do is instantiate a File class with the path you have.
$data = array(
'destino' => 'example#gmail.com',
'asunto' => 'example',
'a_file' => new \Symfony\Component\HttpFoundation\File\File($pathToFile, true)
);
You can use N69S a_file answer
This is basic tips to help you run your command.
Your Kernel.php must be like this
<?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\SendEmailEfsystem::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('emails:send')->everyMonth();
}
/**
* Register the Closure based commands for the application.
*
* #return void
*/
protected function commands()
{
require base_path('routes/console.php');
}
}
Then if you want to run it. Simply run php artisan emails:send
or You want to run it using code you can use Artisan::call('emails:send);
I am creating a console (Artisan) command to run a custom-made package. The import of the package and all of its functions is working just fine, but I can't seem to query any eloquent models without having the following error pop up:
[Symfony\Component\Debug\Exception\FatalErrorException]
Interface 'Illuminate\Contracts\Queue\QueueableCollection' not found
Here is my code...
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Property;
use Sync;
class SyncTool extends Command {
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'sync:all';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$credentials = [
...
];
$sync = new Sync( $credentials );
$properties = Property::all(); // this throws the error
}
}
Step 1 : Remove full vendor folder
Step 2: delete /bootstrap/cache/services.php, /bootstrap/cache/compiled.php
Step 3 : Run from your terminal composer install
try this
For some reason I no longer understand my cron does not work, when I execute the command schedule: run changes are made, however on the server nothing happens, I will explain each step to see if anyone can tell me that I can be doing wrong
this is the code of my command
<?php
namespace App\Console\Commands;
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Plan;
use App\Plan_negocio2;
use App\Plan_negocio;
use App\Pagina;
use DateTime;
use Illuminate\Console\Command;
//use Illuminate\Foundation\Inspiring;
class Resaltador extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'res:resaltado';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Verificar Resaltador';
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$plan=Plan_negocio::all();
//$fechaAct=$request->fecha;
if ($plan)
{
$arrNegocio=[];
foreach ($plan as $key => $value)
{
//$value->fechafin=strtotime("2017-04-07")-time();
date_default_timezone_set('America/Caracas');
$date = new DateTime($value->fechafin);
$dateHoy=new DateTime();
//$dat=$dateHoy->getTimestamp();
$dat=9999999999999999;
$value->fechafin=$date->getTimestamp();
//$now = new DateTime();
//$gene= $date1->format('U') - $now->format('U');
if ($dat>$value->fechafin)
{
$negoPlan=Pagina::find($value->negocio_id);
$negoPlan->resalta_id=1;
$res=$negoPlan->save();
}
}
}
}
}
this, the code of the kernel
<?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 = [
//'App\Console\Commands\Inspire',
\App\Console\Commands\Resaltador::class,
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
/*$schedule->command('inspire')
->hourly();*/
$schedule->command('res:resaltado')->everyMinute();
}
}
When I execute the schedule: run command everything is fine
But as I say, when I try to activate it from the server I do not understand that it can be wrong, I leave the steps
In the folder 'loupper' is where I have stored laravel, with putty I get the path and assign it to the cron jobs manager in cpanel
I don't have composer on the server, but investigating I read that it is not necessary,However nothing happens, what can I be doing wrong?
UPDATE:
I just checked and this email has arrived
/usr/local/cpanel/bin/jailshell: php/home3/pixsony6/public_html/loupper.com/loupper/artisan: No such file or directory
You are missing a space between php and the path in cPanel
I have created an artisan command called sendUnreadNotifications this triggers the system to send users emails if they have unread notifications. Eventually this will be run via a cron job, and a user can either have hourly updates or daily updates.
For this reason I am wanting to send an argument with my command, something like this,
php artisan command:name sendUnreadNotifications H --env=local
However running this, I get the following error,
[RuntimeException]
Too many arguments.
My code, looks like this,
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class sendUnreadNotifications 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()
{
$request = Request::create('api/notifications/send/unread', 'GET', array($this->getArguments()));
Route::dispatch($request)->getContent();
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array(
array('frequency', InputArgument::OPTIONAL, 'How often should the email be sent', 'H'),
);
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array(
array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}
I cannot see why I would be getting the too many arguments exception?
You do only have one argument set, for frequency
protected function getArguments()
{
return array(
array('frequency', InputArgument::OPTIONAL, 'How often should the email be sent', 'H'),
);
}
so the
php artisan command:name sendUnreadNotifications H --env=local
here the H is the argument that is too much. You should change your command's name to what you want to do, the command names need to be unique btw...
Change this:
protected $name = 'command:name';
to
protected $name = 'send:unreadNotifications';
and run your job with
php artisan send:UnreadNotifications H
and it will work.