PHP: Writing a Console Program in CakePHP
By admin on Feb 14, 2008 in Programming, php
I have written my web application in PHP using CakePHP framework, and I need to reuse part of the code in a scheduled job for data extraction. To avoid coding in other language, I was trying to see if it is possible for me to use PHP and CakePHP to run a scheduled job.
To do this in CakePHP is pretty straightforward. I used CakePHP 1.2, and Cake shell is under cake\console directory, and my custom Cake shell is under cake\console\libs directory.
A simple example of a Cake shell.
<?php class MyCustomShell extends Shell { var $tasks = array('Project', 'DbConfig', 'Model', 'Controller', 'View', 'Plugin'); var $txnController = null; function initialize() { $this->_loadModels(); } function main() { App::import('Controller', 'Txns'); $this->txnController = new TxnsController(); $this->txnController->loadHistoricalData(); } function help() { $this->out('Script to load information'); } } ?>
As you can see, my custom shell extends Shell class. $tasks variable is needed since I need to load my CakePHP models and controllers. In main function, I used App::import to import TxnsController so that I can instantiate the class. To load extra model and component, you need to use App::import also, e.g. App::import(’Model’, ‘Txn’) to load Txn model, and App::import(’Component’, ‘Email’) to load the EmailComponent.
To run the console program, I use the script provided by CakePHP to run it.
# <cake_dir>/cake/console/cake my_custom
I can then schedule this command to be run in the interval that I want.
calzone | Nov 21, 2008 | Reply
I tried setting up a console program following your example here but was stymied by the fact that even though a controller action can be invoked from the console, any model method calls that action contains will fail with “Fatal error: Call to a member function on a non-object.”
Am I doing something wrong or is there some additional scoping workaround I need to add to the code somehow somewhere?
calzone | Nov 21, 2008 | Reply
Cakebaker (http://cakebaker.42dh.com/2007/05/07/writing-a-custom-cakephp-console-script/) resolved my issue.
The answer is that after the instantiation, the controller needs to be initialized:
$this->CitiesController = new CitiesController();
$this->CitiesController->constructClasses();
The cake manual mentions this method at http://book.cakephp.org/view/429/constructClasses
oh4real | Dec 5, 2008 | Reply
I’ve set up triggers in Models based on what is being saved or updated. For controller-based access, I used inside the Models:
$this->requestAction(’/mails/method/param1/param2′);
And it worked fine.
BUT, a Shell using the model and making the same save/update got no love as requestAction is banned in ShellDispatcher.
So, I did this and now use it in the Models, whether called by a controller via web interaction or shell called from crontab.
function beforeSave () {
App::import(’Controller’,'Mails’);
$this->MailsController = new MailsController();
$this->MailsController->constructClasses();
$this->MailsController->Email->startup($this->MailsController);
if(save some triggering value) {
$this->MailsController->method1(param1,param2);
} elseif(updating some triggering value) {
$this->MailsController->method2(param1,param2);
}
I am sure there is something horribly wrong with this, but it works and until I learn otherwise…
I also created the EmailTask for Shell specific emails, but might be able to use the code above as well to keep all emails in one location, ie /app/views/elements/emails
regards,
oh4real