Execute a Function in Silverstripe via Cronjob - php

Hi I want to execute a function via cronjob to start an csv import. At the moment the import is triggered by accessing a controller in the browser tld.de/Update
The controller has this code http://pastie.org/8351266
How can I execute the function init() via Cronjob?
Thx!

In SilverStripe you can access any route that is accessible via HTTP also by running cli-script.php in the command line
There also is sake which is just a bash wrapper around cli-script.php (but sake needs to be installed)
so, from your project directory, you can run both commands which will perform the same action (in this case, run a dev/build):
php framework/cli-script.php dev/build
sake dev/build
see the docs for commandline ussage of silverstripe: http://doc.silverstripe.org/framework/en/topics/commandline
the 2nd part of your question (how to call a method from a controller) is actually more a question of routing in silverstripe and has nothing to do with how it is called (cronjob)
I assume that your controller is a Page_Controller or a subclass of that (so bound to a SiteTree Model), then routing is done for you (it takes the URLs you set in the CMS).
so lets see some example code and lets assume you have a page with the URLSegment about:
class Page_Controller extends ContentController {
private static $allowed_actions = array('something');
public function init() {
// the init method will run before every action
// this means this code will run, no matter if you visit /about or /about/something
}
public function index() {
// this is the default action (this code is optional and can be removed),
// and will be called if you visit website.com/about
return $this;
}
public function something() {
// this is the somethingaction,
// and will be called if you visit website.com/about/something
// do something here
return $this;
}
}
you can then call run to get the result of the index():
php framework/cli-script.php about
and this to get the result of something():
php framework/cli-script.php about/something
NOTE: the init method itself is not accessable via URL, it is the "setup" that runs before an action
NOTE: all actions other than index() have to be allowed by adding them to $allowed_actions (also note that you need to ?flush=1 after adding to $allowed_actions to reload the config cache)
EDIT: this was actually the response to your first question, after seeing your code example, this addition:
for standalone controllers it works the same way, just that you have to define the routes, and make sure that you have $Action in the route so that something() can be called

You could do this without Silverstripe sake. Install curl and call the URL via a cronjob, ie:
0 0 * * * curl --silent http://tld.de/Update
The proper way to do this would be to write a Silverstripe task, and invoke your controller from within the task. I haven't tested this code but it would go something like this:
class YourTask extends BuildTask {
public $description = "...";
//...
public function run($request) {
YourController::init();
}
}
You can invoke it over sake using:
0 0 * * * /path/to/framework/sake dev/tasks/YourTask

why not create a build task ? which is specially designed for such requirements (at-least that's how I consider build tasks)
<?php
class ArticleCsvUpdateTask extends BuildTask {
protected $title = 'Article Csv Update';
protected $description = 'Build task for article Csv update';
public function run($request) {
$loader = new ArticleCsvBulkLoader('Color');
if($loader->load('import-new.csv')) {
$loader->load('import-new.csv');
}
}
}
Which can be assess both from browser using "yoursite/dev/tasks/ArticleCsvUpdateTask" and from command line using "php framework/cli-script.php dev/tasks/ArticleCsvUpdateTask" OR using "sake dev/tasks/ArticleCsvUpdateTask" (if you have sake installed).
May be I am not getting your exact requirement but I believe this is much cleaner and nicer way of running a cron job with silverstripe.

See Zauberfisch's answer for a complete solution
I'm not familiar with Silverstripe, but if I understand correctly, this controller init function can be called with a HTTP request.
As the silverstripe docs say, you can call any url from the command line:
php framework/cli-script.php Update/init
More information is available here, and consider using sake for this task.

I think the right way do this is create a php file console like:
#!/usr/bin/env php
<?php
require_once "/path/to/your/class/Update.php";
$class = new Update();
$class->init();
Add right perms to this file
chmod 755 consolefile
And finally run this script with cronjob

Related

Creating Agent and Running every 60 sec. in bitrix24

I have added one function in timeman mosule as follows.
class CTimeManReport extends CAllTimeManReport
{
function testAgent()
{
mail('t#demo.co.in','agent','agent');
return "testAgent();";
}
}
Now I want to run this function every 60 sec.I have added agent though control panel in agent section,but its running only once.
After running the agent bitrix added to database value that agent function returns. So in your case, it must be return "CTimeManReport::testAgent();" because your function is a class method.
Also, it must be a class method, not an instance method, so add public static before your function
So, try to do something like that:
class CTimeManReport extends CAllTimeManReport
{
public static function testAgent()
{
mail('t#demo.co.in','agent','agent');
return "CTimeManReport::testAgent();";
}
}
If this advice doesn't help, you can add cron support for your agents, because by default they work on pages reloads. Follow this link for instructions
P.S. don't add your own code into the bitrix module's code. Because you may lose your code after bitrix updates. Add your own code or include your classes into the local/php_interface/init.php

CodeIgniter - Hourly method call

I'm using CodeIgniter for my project. I have this roadblock in from of me..
There's this method in my controller that I want to call every hour. Let's have that as:
class Notifs extends CI_Controller {
public function __construct() {
parent:: __construct();
// load stuff here
}
public function index() {
}
/* I want to call this function on an hourly basis */
public function check_overdue_stuffs() {
// do the checking here
}
}
I have absolutely no idea on how to implement this. I have tried using sleep($seconds) but that was just a mess.
Any ideas for a perfectly awesome way to do this? A verbose example would be great. Thanks!
This is pretty straight forward, but don't look to just keeping it in your PHP code. You need to use a cronjob script (linux) or windows equivalent (on the server where your software lives).
Here is a simple cron you would add to pull a specific cli method:
# hourly cron
0 * * * * php /www/ciWebsite/index.php [controller] [method] >/dev/null 2>&1
That way, it runs the controller + method you want and output is dumped into /dev/null
Try running /www/ciWebsite/index.php notifs check_overdue_stuff and see if it works (obviously update your path)
edit:
fixed an extra entry (I had cli = folder + controller + method)

CakePHP How to call a controller function from an external function

I'm having trouble with accessing the session in an external .php script located in webroot.
Thought I'd write a function getSession() in one of my controllers and try to call it in the .php file.
So in steps:
I have file.php
In a controller I have a function getSession().
How to call the controllers function in the file.php?
Thank you.
EDIT
Meanwhile I fixed my bug, but still am curious how this is done and want other stack users to find a good answer to this so:
Its exactly like this:
In UsersController I have a function:
public function getSession() {
return $_SESSION['Auth']['User']['user_id'];
}
That I want to let's say print (for example) like this: print_r(Users.getSession) in the file test.php located in webroot/uploadify/test.php.
This file is not a class, but if it is required, then it shall be :)
#CaboOne: Maybe your answer was correct, I just wasnt sure what code to call (and enter) where :)
Supposed I have the following php file in webroot folder:
<?php
class TestingClass {
function getName(){
return "Test";
}
}
?>
I would do the following:
// This would bring you to your /webroot folder
include $_SERVER['DOCUMENT_ROOT'].'/another_file.php';
// Initializing the class
$example = new TestingClass;
// Call a function from the initialized class
$a_value = $example->getName();
// If you want to use $a_value in the view, you can then set
$this->set('a_value', $a_value);

Do _initX() functions get called in sequence

In my bootstrap.php I have many _initX() functions, and some of them may contain code that depends on code in the previous initX
protected function _initAutoloading() { }
protected function _initViewInitializer() { }
protected function _initVariables() { }
So my question, are these _init functions guaranteed to be executed in the exact order they've been declared?
EDIT - To provide a more direct answer to your question, I would say that they probably will be since the code uses ReflectionObjects::getmethods() or get_class_methods depending on your PHP version, so I believe those will return the function in order but there is nothing in the PHP docs or Zend docs that guarantee this will always be the case, so I would not consider this a supported feature.
You can pass the names of the resource functions you want/need to call as part of the bootstrap call: $bootstrap->bootstrap(array('foo', 'bar')); instead of not passing anything and let the Zend Application call them all automatically in which you are not sure of the order.
If you have dependencies in between your bootstrap resources however, I suggest you look at Resource plugins which will allow you to separate your code in different classes and easily call $bootstrap('foo') from within your 'bar' resource plugin code (though you can do so with the _init*() functions as well)
Another benefit of resource plugins is they can be shared with other bootstrap files if you need to and they are easier to test than _init*() functions.
Make sure you read theory of operation document from the Zend Application doc
If you really need them invoked in a particular order, you should use a helper list:
var $init_us = array(
"_initAutoloading",
"_initViewInitializer",
"_initVariables",
);
function __construct() {
foreach ($this->init_us as $fn) {
$this->{$fn}();
}
}
To use that construct in ZF you could rename the example __construct into _initOrderedList and your custom _initFunctions into _myinit... or something.
Read the manual. There are a section called Dependency Tracking :
If a resource depends on another resource, it should call bootstrap() within its code to ensure that resource has been executed. Subsequent calls to it will then be ignored.
Here is sample code :
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initRequest()
{
// Ensure the front controller is initialized
$this->bootstrap('FrontController');
// Retrieve the front controller from the bootstrap registry
$front = $this->getResource('FrontController');
$request = new Zend_Controller_Request_Http();
$request->setBaseUrl('/foo');
$front->setRequest($request);
// Ensure the request is stored in the bootstrap registry
return $request;
}
}
You don't have to rely on the order.

Prevent invocation of instance method X from context != Y

This is a tricky one.
I am "emulating" ZF Bootstrapping (surface appearance). Don't ask me why, call it academic interest. So I have a Bootstrap Abstract with a method "run" that iterates over itself to locate any methods prefixed with "init".
The application looks for a user defined class which extends this class, in which the user can define any number of methods in this way. However, I want to prevent the user from being able to execute the "run" command of it's parent class, while still exposing the same command for the client code.
class Bootstrap_Abstract{
protected final function run(){
// if method exists that starts 'init' - execute the method
}
}
class Bootstrap extends Bootstrap_Abstract(){
public function initSomething(){
//do something
}
//PREVENT THIS
public function initRun(){
$this->run();
}
}
//application code, not exposed to user - changes in behaviour require changes in this code directly
class Application(){
$Bootstrap = new Bootstrap();//load user bootstrap
$Bootstrap->run();
}
To determine "what" called a particular method, look into debug_backtrace
Post Script:
the problem with my original code was an error in design. The responsibility for iterating through the Bootstrap methods should have been given to the invoking class, not the target class itself.
I solved this problem by moving the function out to the invoker. Funny how obvious/simple refactoring is in hindsight...

Categories