Is it possible to use phalcon in cli applications to handle requests with argv parameters?
I want to use argv parameters to understand command that should be executed, e.g.
./script.php robot/create --color=red --feature=weapon
and to get this inside my application with controllers, actions, etc in this way:
controller: robot
action: create
GET params: color=red,feature=weapon
Is it possible using CLI classes like
Phalcon\ClI\Dispatcher
http://docs.phalconphp.com/en/latest/api/Phalcon_CLI_Dispatcher.html
Phalcon\CLI\Console http://docs.phalconphp.com/en/latest/api/Phalcon_CLI_Console.html
Phalcon\CLI\Task http://docs.phalconphp.com/en/latest/api/Phalcon_CLI_Task.html
and other similar?
There are no docs and how-to manuals... Perhaps somebody has experience or just an idea.
I understand that we have to define DI and initialize application, but how to make this in a more native way I just don't have any ideas.
Also, one more question: can phalcon handle argv parameters automatically?
As I understand, we should start Phalcon\CLI\Console object as application and pass to it DI. But the whole process/scenario... I just can't get it :)
So, i have following folders structure:
~/www
~/www/app
~/www/app/models
~/www/app/controllers - controllers for web
~/www/app/tasks - task for cli
~/www/public/app.php - web application
~/www/cli/app.php - console application
In cli/app.php i have following code:
#!/usr/bin/php
<?php
/**
* This makes our life easier when dealing with paths.
* Everything is relative to the application root now.
*/
chdir(dirname(__DIR__));
/**
* Init loader
*/
$loader = new \Phalcon\Loader();
$loader->registerDirs(['app/tasks/'])
->register();
/**
* Setup dependency injection
*/
$di = new Phalcon\DI();
// Router
$di->setShared('router', function() {
return new Phalcon\CLI\Router();
});
// Dispatcher
$di->setShared('dispatcher', function() {
return new Phalcon\CLI\Dispatcher();
});
/**
* Run application
*/
$app = new Phalcon\CLI\Console();
$app->setDI($di);
$app->handle($argv);
then i put my tasks classes in app/tasks folder.. and it just works.
perhaps this will help somebody ;)
I'm a Phalcon enthusiast, but actually tasks seem to me something to create cron jobs. They are something different from commands. I don't think tasks are the right way to create a complete cli application. There are many limitation. I really suggest you to use Symfony Console instead: it's well documented, it manages multi arguments and params, it provides automatically a command line help and you can install it via Composer.
If you are creating cron jobs you can go with Phalcon tasks, but if your intention is to create a cli application, take a look at Symfony Console.
can phalcon handle argv parameters automatically?
yes, PHP will pass command line parameters to $argv in any framework.
Related
I have an interface UserIdProvider that has two implementations:
ConsoleUserIdProvider - it takes user id from CLI input option
RequestUserIdProvider - it comes from {userId} parameter in route
How should I configure Kernel to inject console implementation when I run CLI only, and how to use second one when it is regular request to web server?
I created separate ConsoleKernel extends Kernel for console.php where I load:
$loader->load($confDir . '/console_services.yml');
But unfortunately it overrides via cache in APP_ENV=prod mode regular Kernel where RequestUserIdProvider is supposed to be used.
Thanks in advance.
I figured it out. I should create new cli environment for that purpose.
I removed ConsoleKernel that loads custom yml file. It's not necessary.
I renamed console_services.yml to follow Symfony practice, which is supposed to be: services_cli.yml in my case. My console specific implementation is placed there.
I also changed console.php to disable debug mode in cli environment like for prod:
$notLikeProdEnv = !in_array($env, ["prod", "cli"], true);
$debug = ($_SERVER['APP_DEBUG'] ?? $notLikeProdEnv) && !$input->hasParameterOption(['--no-debug', '']);
Thanks to that when I run php console --env=cli I can see only commands specific to cli environment and also my ConsoleUserIdProvider implementation.
I need to run a cron job to do a sql query and save the data in the database every 24 hours.
I have a controller called GetproductsController.php and the method I have to execute is indexAction()
I've tried to do it this way:
5,10,15,20,25,30,35,40,45,50,55,59 * * * * /usr/bin/curl --silent http://localhost:8080/myproject/getproducts/index
But I donĀ“t know how to do it, If anyone knows how I can do it, I would appreciate it.
Regard!
You need to create a cli bootstrap for your project.
Default application class for web applications is \Phalcon\Mvc\Application. Instead, you should use \Phalcon\Cli\Console for cli applications.
Default DI class for web applications is \Phalcon\Di\FactoryDefault. Instead, you should use \Phalcon\Di\FactoryDefault\Cli for cli applications.
Default Dispatcher class for web applications is Phalcon\Mvc\Dispatcher. Instead you should use Phalcon\Cli\Dispatcher for cli applications.
Default Router class for web applications is Phalcon\Mvc\Router. Instead you should use Phalcon\Cli\Router for cli applications.
Please note that the classes that I've mentioned are for Phalcon 2.0. I'm not sure if they are the same for Phalcon 3.
Here is the documentation for cli applications in phalcon.
You can use the same config file with a few if statements. For example :
if (php_sapi_name() == "cli") {
$di = new Phalcon\Di\FactoryDefault\Cli();
} else {
$di = new Phalcon\Di\FactoryDefault();
}
if (php_sapi_name() === "cli") {
$di->set('dispatcher', function() {
$dispatcher = new Phalcon\CLI\Dispatcher();
$dispatcher->setDefaultNamespace('Project\\Tasks');
return $dispatcher;
});
} else {
$di->set('dispatcher', function() {
$dispatcher = new Phalcon\Mvc\Dispatcher();
$dispatcher->setDefaultNamespace('Project\\Controllers');
return $dispatcher;
});
}
You might be able to use controller classes with cli routing. But I would recommend using independent tasks.
After creating cli bootstrap file (let's call it cli.php) you can add shebang for php #!/usr/bin/env php and make that file executable. Then you can run your tasks as cli.php {taskname}
It doesn't seem like what you want to do is possible (calling a controller method from the cron). Personally, I would try to use the Phalcon CLI from their documentation: https://docs.phalconphp.com/en/latest/reference/cli.html
curl is another option. For that, first determine where curl is located on your server with:
which curl
The result of this command will be a path on the filesystem such as /usr/bin/curl. Use that result in the place of [path to curl] in the cron command below.
you would do:
59 23 * * * [path to curl] --silent https://mypage/getproducts/index &>/dev/null
My existing Laravel project is such that all the tasks are executed sequentially. I have identified part of the code which can be run in parallel using PHP threads and can reduce the response time.
Instead of using pthreads, there was suggestion given that why not use appserver.io - which is fully multithreaded php server itself. One can use its MessageQueue feature, add all your job to this queue, and it will automatically fork worker threads. You don't have to manage anything.
I have already deployed existing Laravel app on appserver.io (copied project under /opt/appserver/webapps/ folder) but now I don't know how to use appserver's MessageQueue. My project uses psr-4, where as appserver is psr-0. Laravel has it's own DI and so does appserver.
All I want to do is, use appserver's MessageQueue to get more workers executing one function in parallel. I'm new to appserver and not sure how the directory structure should look like or what configuration I have do it. Any pointers will be helpful.
you can connect and send to the MessageQueue from within your Laravel application. First you've to install the client library appserver-io/messaging by adding "appserver-io/messaging" : "~1.0" to your composer.json. Then you can send a message with
$queue = MessageQueue::createQueue('pms/myQueue');
$connection = QueueConnectionFactory::createQueueConnection('my-laravel-app');
$session = $connection->createQueueSession();
$sender = $session->createSender($queue);
$sender->send(new StringMessage('Some String'));
assuming you've an application named my-laravel-app, that resides in the folder /opt/appserver/webapps/my-laravel-app and a MessageQueue called pms/myQueue, defined in a file META-INF/message-queues.xml. The file would look like
<?xml version="1.0" encoding="UTF-8"?>
<message-queues xmlns="http://www.appserver.io/appserver">
<message-queue type="MyReceiverClass">
<destination>pms/myQueue</destination>
</message-queue>
</message-queues>
In that example, the receiver class MyReceiverClass has to be available under /opt/appserver/webapps/my-laravel-app/META-INF/classes/MyLaravelApp/Receivers/MyReceiverClass for example.
A good start is the example application that comes with simple MessageQueue example running some simple import functionality.
Original Post
Good evening folks. I have a laravel setup and I'm trying to have a cronjob execute a php function to a file within the laravel project directory.
I am getting class and name space errors when I try to do something like this:
<?php
require_once('../laravel/app/Http/Controllers/NotificationsController.php');
and then calling the processQueuedNotifications() function.
This of course gives me errors, what is the correct way to call my function within the laravel directory? I need to call this function as this function has all the correct namespaces and extended controllers necessary to execute the function properly.
Update 1:
Thanks to #michael, I've been made aware of a component in Laravel called commands.
So I ran this code:
php artisan make:console processQueuedNotifications
and it created some files in the console directory.
Currently exploring on what to do next.
After checking out the Events class which the kernel.php file makes use of, I noticed that this class provides an easy to use interface for me to create cron jobs on the fly. Am I correct in think so?
I notice there is not function to run a cron job every minute, is it safe to edit the Events class file without it being overwritten by future make:console commands, or laravel updates?
I saw this code in the kernel.php file:
$schedule->command('inspire')
->hourly();
So is this the place you wanted me to add my function? as I notice that the inspire function is something automatically created for me to understand what's going on?
So I would write,
$schedule->command('processQueuedNotifications')
->everyMinute();
//Providing it's safe to edit the Event's class or figure out a clean way of doing so without my code being deleted in the future on Laravel updates.
A very convenient way is to use laravels console component. You can create a new command by issuing
php artisan make:console
And find it thereafter in your app/console directory. Make sure to enable the command in the Kernel.php file once created.
Simply call your class or whatever you want to run via cron from inside the command. The console command itself is callable via cli just as you would run one of laravels php artisan ... commands. You can set this in the file created for you. For example, you can then call the file from everywhere you want with
/usr/bin/php /path/to/file/artisan my:command
You can set options and arguments if you need to.
Here's the documentation: http://laravel.com/docs/5.0/commands / http://symfony.com/doc/current/components/console/introduction.html
There's an array in kernel.php you need to register your class (include the namespace) in. After that it is callable via cli. For a start, have a look on arguments and options you can initialize in case you need to make different requests on your controller class. (The filename you have chosen for your console command, is an argument. You can make them required or optional for your own commands. )
Within your file, you can create them by simply creating an array in the appropriate method with these values:
[$name, $mode, $description, $defaultValue]
have a look at the docs or Jeffrey's laracasts, they are very good.
To only call your class from the console command, it's enough to name your command in the above section of the file and call you controller like
(new namespace\controller)->method();
What you can do in your code, after your update, 2 choices :
Dispatching directly the command from your code using the Bus facade
first import it using the
use Illuminate\Support\Facades\Bus;
then in your code
Bus::dispatchNow(new YourCommandClass);
(don't forget to import your command class)
Dispatch it for queue process using the same bus facade:
(still importing the same way)
Bus::dispatch(new YourCommandClass);
(Note that in that case, you'll need to have the following command run by your cron job :
php artisan queue:listen
it can handle several options such as the --tries=X where is is the number of tries etc
Generally speaking, you can get more info from commands typing php artisan my:command -h
I'm about to start writing a Symfony2 application and I've come across some notes I must have written a while back about ensuring I write Symfony2 controllers with the fact it needs to be ran from the command line too.
Rather than bash out a load of controllers and seemingly be happy they work in a web browser, I want to ensure all controllers work on the command line too.
A lot of them will need to be ran from the command line, e.g. Cron Tasks etc.
(1) My notes tell me to insert this in AppKernel.php:
* This prevents a 'You cannot create a service ("request") of an inactive scope ("request")' error
<?php
class AppKernel extends Kernel
{
protected function initializeContainer() {
parent::initializeContainer();
if (PHP_SAPI == 'cli') {
$this->getContainer()->enterScope('request');
$this->getContainer()->set('request', new \Symfony\Component\HttpFoundation\Request(), 'request');
}
}
}
?>
(2) I've also got a pre-written request listener that runs various code on every request, and I'm aware the variables generated won't be used on the command line.
(3) I know that none of my Apache config will run (as it's not running inside Apache), and I also know that there's two php.ini files (CLI and Apache).
What else do I need to consider?
What else isn't available on the command line compared to a browser?
I would consider Console Component.
Symfony 2 has a build in interface for creating CLI based commands that will have the entire application bootstrapped, it's called Console Component.
Build out your cronjobs and tasks using this and you can use dependency injection to ensure you have all of the services you need.
I'm sure with some research you could figure out how to load a controller if necessary--controller forwarding or virtual?