RSS Feed for This PostCurrent Article

PHP: Writing a Console Program in CakePHP

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.


Trackback URL


RSS Feed for This Post3 Comment(s)

  1. 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?

  2. 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

  3. 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

Sorry, comments for this entry are closed at this time.