I know it's possible to schedule commands to be run with laravel and cron job, my goal is tro create a command to backup my sql databases into my home directory inside my VPS, the example I found uses laravel storage path to drop the backups but I was wondering how can I choose another file outside my laravel app folder (my user home directory for example), is it possible to do?
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class BackupDatabase extends Command
{
protected $signature = 'db:backup';
protected $description = 'Backup the database';
protected $process;
public function __construct()
{
parent::__construct();
$this->process = new Process(sprintf(
'mysqldump -u%s -p%s %s > %s',
config('database.connections.mysql.username'),
config('database.connections.mysql.password'),
config('database.connections.mysql.database'),
storage_path('backups/backup.sql')
));
}
public function handle()
{
try {
$this->process->mustRun();
$this->info('The backup has been proceed successfully.');
} catch (ProcessFailedException $exception) {
$this->error('The backup process has been failed.');
}
}
}
Related
I am having trouble externally processing jobs on the queue while in test mode using PHPUnit. I have a job that writes a message to the the log file which is dispatched when I visit a route, I thought it could work like the way it does in development where there is a terminal window listening for work with php artisan queue:work and the other running server.
Test.php
public function testBasicTest()
{
$message = "Sample message job " . date("l jS \of F Y h:i:s A");
$filename = "laravel.log";
$this->json('GET', route('test.test-try-log-job'), ['message' => $message]);
$this->assertDatabaseHas('jobs', [
'id' => 1,
]);
exec('php artisan queue:work'); // Artisan::call("queue:work");
}
Controller
class TestController extends Controller
{
public function tryLogJob(Request $request){
dispatch(new TestJob($request->message))->onQueue('default');
return response()->json(['success'=>true], Response::HTTP_OK);
}
}
Job
class TestJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $message;
public function __construct($message)
{
$this->message = $message;
}
public function handle()
{
Log::info($this->message);
sleep(5);
}
}
when I use Artisan::call("queue:work"); the job is processed but when I use exec('php artisan queue:work');, it is not processed.
Is there a way I can get this to work? I really need to use the exec() function.
The phpunit.xml was configured to SQLite but the .env file was configured to MySQL.
During the test the job was being added to SQLite and not MySQL on which exec('php artisan queue:work'); is run.
I set the database variables in phpunit.xml to match those .env (MySQL) and the jobs are being handled correctly.
in db i have column visit_clear i want it 0 after one day so i used this code
in kernal.php
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
];
protected function schedule(Schedule $schedule)
{
$schedule->command('cron:update-user-not-new')->daily();
}
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
and in command/UpdateUserNotNew.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class UpdateUserNotNew extends Command
{
protected $signature = 'cron:update-user-not-new';
protected $description = 'Command description';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$dayAgo = 1; // Days ago
$dayToCheck = \Carbon\Carbon::now()->subDays($dayAgo)->format('Y-m-d');
Customer::whereDate('visit_date', '<=', $dayToCheck)
->update([
'visit_clear' => 0
]);
}
}
i am sheduling commnd like this as u can see cron:update-user-not-new should i use crone:UpdateUserNotNew?
You need to register your command in Kernel.php like this:
protected $commands = [
'App\Console\Commands\UpdateUserNotNew',
];
You should then be able to run the command manually with php artisan cron:update-user-not-new
In order for the automatic running of the command to work, you need to add an entry to your system's task scheduler, as this is what Laravel uses to run commands on a schedule.
Assuming you are using Linux, you need to add an entry to your crontab. To do this, in a command prompt enter crontab -e, hit enter, and add this line:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
Don't forget to replace /path-to-your-project with the root folder of your project
Once done editing the crontab, save and close the editor and the new entries should be installed, and your command should now run on the schedule.
All this info came from https://laravel.com/docs/7.x/scheduling so if you need more info take a look there
I can get arguments in command with this code:
$this->argument();
But how to get arguments outside ?
If I look at source of argument() function I see :
public function argument($key = null)
{
if (is_null($key)) {
return $this->input->getArguments();
}
return $this->input->getArgument($key);
}
I want to detect when command "php artisan migrate:refresh --seed" is running because I want some part of code in models run at localhost enviroment but not in localhost enviroment during seeding...
Mechanism how laravel gets command arguments is pretty complicated. I can detect if app is running in console with \App::runningInConsole() but there is no function which will get arguments, something like :
if(\App::runningInConsole()){
$args = \App::getConsoleArguments(); // doesn't exist :(
}
but $_SERVER['argv'] can be usefull here, when "php artisan migrate:refresh --seed" is running in $_SERVER['argv'] is this array:
Array
(
[0] => artisan
[1] => migrate:refresh
[2] => --seed
)
so I can use this code:
if( ! empty($_SERVER['argv'][2] ) && $_SERVER['argv'][2] == '--seed'){
//
}
I has the same problem building a Laravel SAAS app on AWS, in base to this project I modify my ServiceProvider for this:
<?php
namespace App\Providers;
use Illuminate\Console\Events\ArtisanStarting;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\EventDispatcher\EventDispatcher;
class MultitenantServiceProvider extends ServiceProvider{
protected $consoleDispatcher = false;
protected $commands_with_tenant = [
'migrate', 'migrate:refresh', 'migrate:install', 'migrate:reset', 'migrate:rollback',
'migrate:status', 'passport:client', 'passport:install', 'passport:keys'
];
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot(){
if( $this->app->runningInConsole() ){
$this->registerTenantOption();
$this->verifyTenantOption();
}
// Multitenant re-configure in case of HTTP request
}
/**
* Register any application services.
*
* #return void
*/
public function register(){
$this->app->singleton('multitenant', function ($app){
// Register your Multitenant
});
}
protected function registerTenantOption(){
$this->app['events']->listen(ArtisanStarting::class, function($event){
$definition = $event->artisan->getDefinition();
$definition->addOption(
new InputOption('--tenant', null, InputOption::VALUE_OPTIONAL, 'The tenant subdomain the command should be run for. Use * or all for every tenant.')
);
$event->artisan->setDefinition($definition);
$event->artisan->setDispatcher($this->getConsoleDispatcher());
});
}
protected function verifyTenantOption(){
$this->getConsoleDispatcher()->addListener(ConsoleEvents::COMMAND, function(ConsoleCommandEvent $event){
if( in_array($event->getCommand()->getName() , $this->commands_with_tenant) ){
$tenant = $event->getInput()->getParameterOption('--tenant', null);
if (!is_null($tenant)){
if ($tenant == 'all'){
// Do something with 'all'
}
else{
// Do something with $tenant
}
}
else{
$event->getOutput('<error>This command need that specified a tenant client</error>');
$event->disableCommand();
}
}
});
}
protected function getConsoleDispatcher(){
if (!$this->consoleDispatcher){
$this->consoleDispatcher = app(EventDispatcher::class);
}
return $this->consoleDispatcher;
}
In this class, there is an array with the commands that are needed to verify and use a multitenant config.
I am using windows.
My code on \app\Console\Kernel.php is like this:
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
Commands\CustomCommand::class,
];
protected function schedule(Schedule $schedule)
{
$schedule->command('custom:command')
->everyMinute();
}
protected function commands()
{
require base_path('routes/console.php');
}
}
My code on \app\Console\Commands\CustomCommand.php is like this:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use DB;
class CustomCommand extends Command
{
protected $signature = 'custom:command';
protected $description = 'test cron job to update status on table order';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$id = 1;
DB::table('orders')
->where('id', $id)
->update(['status' => 2, 'canceled_at' => date("Y-m-d H:i:s")]);
}
}
I run php artisan list to see my cron job
After find my cron job (custom:command), then I run my cron job with like this : php artisan custom:command
It's successful update status = 2. After that I change the status manually again become 1, and then I wait one minute, it does not update status again
Is there anyone can help me?
You should also set cron on your local web server to run cron jobs.
How you change the status manually?
You change it in the database?
maybe the cron is running but 'id' int the database is equal to '2' and maybe this is why you dont see any change!
If you look for a better way to check if the Cron job is working
just add Log that will wroth to the log file
public function handle()
{
Log::info('Cron job working'); // you can also print variables
$id = 1;
DB::table('orders')
->where('id', $id)
->update(['status' => 2, 'canceled_at' => date("Y-m-d H:i:s")]);
}
Don't forget to had the Log to your source:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use DB;
use Log; // Here
class CustomCommand extends Command
I'm creating a command for sending an email automatically daily.
I'm creating the command like this:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
class SendEmail extends Command
{
protected $signature = 'emails:send';
protected $description = 'Sending emails to the users.';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$data = array(
'name' => "МГ 'Константин Величков', гр. Пазарджик",
);
Mail::send('emails.test', $data, function ($message) {
$message->from('mg.kvelichkov#gmail.com', 'МГ "Константин Величков"');
$message->to('yoannam1502#gmail.com')->subject('Оценки');
});
$this->info('The emails are send successfully!');
}
}
And then register it in Kernel like this:
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected $commands = [
Commands\Inspire::class,
Commands\SendEmail::class,
];
protected function schedule(Schedule $schedule)
{
$schedule->command('emails:send')->daily();
}
}
I'm listing all artisan commands and i can see my new comand emails:send - therefore its created, but when i try to run it (php artisan emails:send) i got this:
[Swift_TransportException] Process could not be started [The system
cannot find the path specified. ]
What is the problem?
It seems Gmail is blocking sending emails or your environment blocks connection.
Go to this address to unlock your Gmail account. Also, check firewall settings on your server.