I want to be able to run a controller's method from URL, and from the console. How can I do that? I mean, having a method in some controller:
/**
* #Route("/fooBar", name="fooBar")
*/
public function actionFooBar() {
$this -> get('file') -> saveSomethingToSomeFile();
return 'a';
}
I want to be able to open it via http://domain.com/fooBar and php app/console fooBar, or something like this.
The console one doesn't work. How can I solve this?
What you want is (I think) technically doable, but not good practice.
You should move the code in your controller method to a service, then you can run that same code from both your command and your controller.
You need to build a Command:
<?php
namespace Application\CommandBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\ORM\EntityManager;
/**
* Class testCommand
* #package Application\CommandBundle\Command
*/
class TestCommand extends ContainerAwareCommand
{
/**
* Configuration of the command
*/
protected function configure()
{
$this
->setName('command:do:something')
->setDescription('This command does something');
}
protected function initialize(InputInterface $input, OutputInterface $output)
{
}
/**
* #param InputInterface $input An InputInterface instance
* #param OutputInterface $output An OutputInterface instance
*
* #return null|int null or 0 if everything went fine, or an error code
*/
protected function execute(InputInterface $inputInterface, OutputInterface $outputInterface)
{
$outputInterface->writeln(
'This command does something <info>' . $inputInterface->getOption('env') . '</info> environment'
);
$this->getContainer()->get('application_command.test')->doSomething();
$outputInterface->writeln('Done');
}
}
More info with details: https://extractcode.com
Related
I need to run the controller method every 2 hours. I read somewhere that you need to create a command and run this command by using CRON. It is correct?
MY COMMAND:
namespace AppBundle\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Routing\Annotation\Route;
class RunCommand extends Command
{
// the name of the command (the part after "bin/console")
protected static $defaultName = 'app:run';
protected function configure()
{
// ...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
echo 'BEGIN';
$controller = new \AppBundle\Controller\DefaultController();
$controller->storeAction();
echo 'END';
}
}
MY CONTROLLER:
/**
* #Route("/to-db", name="to-db")
*/
public function storeAction()
{
$entityManager = $this->getDoctrine()->getManager();
$data = new Skuska();
$data->setName('Keyboard');
$entityManager->persist($data);
$entityManager->flush();
// die();
}
My error: In ControllerTrait.php line 424: Call to a member function has() on null
Is my code correct? How do I run a method using cron?
I don't want to use another bundle. I want to program it myself
As mentioned in the comments, you should move the logic out of the controller and into a service, and use that service both in the command and in the controller.
With the default service autoloading configuration, you don't even have to care about your service declarations. Your command will automatically be a service, and you can inject other services into it.
https://symfony.com/doc/current/console/commands_as_services.html
For controllers, you don't even need to use a specific constructor.
https://symfony.com/doc/current/controller.html#fetching-services
<?php
// AppBundle/Service/StoreService.php
use AppBundle\Entity\Skuska;
use Doctrine\ORM\EntityManager;
class StoreService
{
/** #var EntityManager */
private $entityManager;
/**
* StoreService constructor.
* #param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function store()
{
$data = new Skuska();
$data->setName('Keyboard');
$this->entityManager->persist($data);
$this->entityManager->flush();
}
}
<?php
// AppBundle/Controller/StoreController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use AppBundle\Service\StoreService;
class StoreController extends Controller
{
/**
* #Route("/to-db", name="to-db")
* #param StoreService $storeService
* #return Response
*/
// Hinting to you service like this should be enough for autoloading.
// No need for a specific constructor here.
public function storeAction(StoreService $storeService)
{
$storeService->store();
return new Response(
// Return something in you response.
);
}
}
<?php
// AppBundle/Command/RunCommand.php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use AppBundle\Service\StoreService;
class RunCommand extends Command
{
protected static $defaultName = 'app:run';
/** #var StoreService */
protected $storeService;
/**
* RunCommand constructor.
* #param StoreService $storeService
*/
public function __construct(StoreService $storeService)
{
$this->storeService = $storeService;
parent::__construct();
}
protected function configure()
{
// ...
}
protected function execute(InputInterface $input, OutputInterface $output)
{
echo 'BEGIN';
$this->storeService->store();
echo 'END';
}
}
I'm trying to extend my Laravel Artisan commands with a trait. The trait should capture all command line output and send it to Slack.
I've got the 'send messages to slack' part working with this package.
However I'm failing to capture the console output. This is what I've got:
namespace App\Traits;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
trait NotifiesSlack
{
/**
* Execute the console command.
*
* #param \Symfony\Component\Console\Input\InputInterface $input
* #param \Symfony\Component\Console\Output\OutputInterface $output
* #return mixed
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$consoleOutput = new BufferedOutput;
$call = $this->laravel->call([$this, 'handle']);
$this->notifySlack($consoleOutput->fetch());
return $call;
}
public function notifySlack(string $output)
{
\Slack::send($output);
}
}
Am I overriding the right method? Are there other ways to capture the console output from the Command class?
Any help is welcome! Thanks in advance.
You are experiencing usual case of not able to override method via trait. It's obviously because the execute method is already declared in the class itself rendering the trait useless.
A quick and easy way, is to simply create your own abstract command class that extends the Illuminate\Console\Command; and override the execute method to your liking; afterwards use the abstract command class for your slack-reportable commands as base.
abstract class NotifiesSlackCommand extend Illuminate\Console\Command {
protected function execute(InputInterface $input, OutputInterface $output)
{
...
}
}
And real command that needs send to Slack
class ProcessImagesCommand extends NotifiesSlackCommand {
public function handle() {/* do magic */}
}
I´m trying to create $schedule job in Laravel to read Email with PHP IMAP package. If I go to route, package read email and does all correctly, but need to do this every 5 minutes.
I create a new command class and add this
use Illuminate\Http\Request;
class ReadMail extends Command implements SelfHandling {
protected $name = 'read:mail';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the command.
*
* #return void
*/
public function fire()
{
$request = Request::create($this->option('App\Http\Controllers\MailController#index'), 'GET');
$this->info(app()['Illuminate\Contracts\Http\Kernel']->handle($request));
}
In kernel
protected $commands = [
'App\Console\Commands\ReadMail',
];
protected function schedule(Schedule $schedule)
{
$schedule->call('read:mail')
->everyFiveMinutes();
}
I'm not sure if this code it´is correct, but does not work properly. Any idea about it?
Thank in advance for your help.
UPDATE
I launch this
php artisan read:mail and return
Argument 1 passed to Illuminate\Console\Application::add() must be an instance of Symfony\Component\Console\Command\Command, instance of App\Commands\ReadMail given
The code of ReadMail class
<?php namespace App\Commands;
use App\Commands\Command;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Http\Request;
class ReadMail extends Command implements SelfHandling {
protected $signature = 'read:mail';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the command.
*
* #return void
*/
public function fire()
{
$request = Request::create($this->option('App\Http\Controllers\MailController#index'), 'GET');
$this->info(app()['Illuminate\Contracts\Http\Kernel']->handle($request));
}
}
UPDATE 2: SOLVED - ALL CODE
Kernel
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\Commands\ReadMail',
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('read:mail')
->everyFiveMinutes();
}
}
ReadMail
<?php namespace App\Commands;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Http\Request;
use Illuminate\Console\Command;
use App\Http\Controllers\MailController;
class ReadMail extends Command implements SelfHandling {
protected $name = 'read:mail';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the command.
*
* #return void
*/
public function handle()
{
MailController::index();
}
}
MailController
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use PhpImap\Mailbox as ImapMailbox;
use App\Models\Escalas;
class MailController extends Controller {
public static function index()
{
$mailbox = new ImapMailbox('{imap.gmail.com:993/imap/ssl}INBOX', '', '','');
$mailsIds = $mailbox->searchMailbox('UNSEEN');
if(!$mailsIds) {
die('Mailbox is empty');
}
$mail=[];
foreach ($mailsIds as $index=>$data){
$mail[]=$mailbox->getMail($mailsIds[$index]);
Escalas::insert([
['' => $mail[$index]->textPlain,
'' => $mail[$index]->date,
''=>$mail[$index]->subject,
''=>$mail[$index]->fromName,
''=>$mail[$index]->fromAddress,
''=>$mail[$index]->toString],
]);
}
}
}
Try changing
protected $name = 'read:mail';
with protected $signature= 'read:mail';
in your ReadMail class and then run in Kernel like this
$schedule->command('read:mail')->everyFiveMinutes();
Check whether your scheduled tasks are set up properly (see docs for Laravel 5.0) Make sure you've added a cronjob to trigger Laravel's scheduled commands. To check you cronjobs are running, look for a file like /logs/crond.log. When opening this file, you should see lines showing at what times this ran. This is the command that triggers Laravel's scheduled jobs.
If all that is correct, then try running your command via your terminal on localhost to check the command is all set. This should reveal any problems with the command setup. Your functionality itself seems allright, since you mentioned everything works when triggered via a route.
I do
when I run artisan queue:work or artisan queue:listen it runs the current commands with their corresponding Arguments. Now my question is, how can I Access those Arguments?
As you can see in the following Picture, the Arguments are there but I have no clue how to Access them?
In a project which follow a "standard project structure"
You must have a class in app/Console named Kernel which extends Illuminate\Foundation\Console\Kernel, an example of how to implement it is as follows:
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* {#inheritdoc}
*/
protected $commands = [
//here you have to put your commands class
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
protected function schedule(Schedule $schedule): void
{
}
/**
* Register the Closure based commands for the application.
*
* #return void
*/
protected function commands(): void
{
require base_path('routes/console.php');
}
}
so now let's create a new command, call it "print" and it will accept a parameter called text, here is the implementation :
<?
namespace App\Console\Commands;
use Illuminate\Console\Command;
class TestCommand extends Command
{
/**
* {#inheritdoc}
*/
protected $signature = 'test {text}';
/**
* {#inheritdoc}
*/
protected $description = 'Test command.';
/**
* {#inheritdoc}
*/
public function handle()
{
$this->info($this->argument('text'));
}
}
as you can see, the new command accept a parameter called text and print it in console.
So to retrieve the parameter sent to an command call, you have to use the argument method in the follow way:
$commandInstance->argument('key_of_parameter');
To get more info read the docs
I have Symfony 2.6.11 I use cron and I need run some script
$all_developer = $em->getRepository('ArtelProfileBundle:Developer')->findAll();
foreach ($all_developer as $session_developer) {
//some logic
}
I know how to run app/console 'somne comand' but if I need run some code I don't know how this code run.
Help how add this code in app/console or any solved ??
You can see a command example (source) over here:
<?php
namespace Application\CommandBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\ORM\EntityManager;
/**
* Class testCommand
* #package Application\CommandBundle\Command
*/
class TestCommand extends ContainerAwareCommand
{
/**
* Configuration of the command
*/
protected function configure()
{
$this
->setName('command:do:something')
->setDescription('This command does something');
}
protected function initialize(InputInterface $input, OutputInterface $output)
{
}
/**
* #param InputInterface $input An InputInterface instance
* #param OutputInterface $output An OutputInterface instance
*
* #return null|int null or 0 if everything went fine, or an error code
*/
protected function execute(InputInterface $inputInterface, OutputInterface $outputInterface)
{
$outputInterface->writeln(
'This command does something <info>' . $inputInterface->getOption('env') . '</info> environment'
);
$this->getContainer()->get('application_command.test')->doSomething();
$outputInterface->writeln('Done');
}
}
In that example the code gets the application_command.test service and will run the doSomething() method of that service/class:
$this->getContainer()->get('application_command.test')->doSomething();