public function updateStatus() /* Set status to 'closed' for any quotes that have reached their expiry date*/
{
$criteria=new CDbCriteria;
$criteria->condition="quote_status < 5";
$criteria->addCondition("expiry_datetime <= '".date('Y-m-d H:i:s')."'");
$quotes=$this->findAll($criteria);
foreach($quotes as $quote)
{
$quote->quote_status=7;
$quote->update();
}
}
I run this function in my controller actions:
$model->updateStatus(); // update quote status
The only problem is of course that the record only gets updated when the user accesses that particular action. There are several other actions that would depend on this method. I can obviously call the method on each and every action but are there any other ways of doing this? For example can it be called each time the model is accessed? Or in the loadModel() controller function?
you can build a global controller class, and let every controller implement it, in the global controller class, you should override the init() method, in it you can do what you want to.
<?php
class MyController extends Controller
{
public function init()
{
//your code
}
}
But i still think that, andy_s is right that to use cron to do it.
That’s a good suggestion, but I’m deep in to the development of this app and don’t really want to change the structure at this stage. Plus it’s easier for me to test the app by altering the status directly in the database (there are 5 status values).
I think I will just call the method on each action and monitor the performance!
So, I have a workaround for you. Modify status at afterFind:
quote model:
public function afterFind(){
if ($this->expiry_datetime <= date('Y-m-d H:i:s')){
$this->quote_status = '7';
$this->update(); // think about this, it can decrease performance.
}
return parent::afterFind();
}
I assume for that to work I would have to change the max_execution_time setting in PHP, because the script would be running for 1 hour each time right? Do you have an example do demonstrate?
Ha! Thanks for pointing that out. I’ve written my own “daemon” some time ago and totally missed that there’s something in PEAR. That makes me think: How cool would a class CDaemon (extends CConsoleApplication) be? On the other hand, making a class like this cross platform safe is surely a nightmare.
I wouldn’t mind if you shared your console runner class.
Would be very useful. Especially for people who cannot install PEAR packages on their host.
I am curious how you use it with your Mutex class. I’ve tried to detect if the process was running and then inform my app that it ended, but I just end up with either prematurely killed processes or a never ending poll.
I’ll try it with the daemon class (if I can convince my host to install it).
I needed to monitor some service, so i’ve implemented it as a yiic command. It’s a very simple implementation, nothing special. See for yourself:
<?php
class DaemonCommmand extends CConsoleCommand
{
public function run($args)
{
// Try to create / lock PID file before proceeding.
// If this fails, another script is already running.
$pidfile = Yii::getPathOfAlias('application.runtime.daemon').'.pid';
$fp = fopen($pidfile,"a+") or die('Could not create pidfile: '.$pidfile."\n");
flock($fp,LOCK_EX | LOCK_NB) or die("Could not lock pidfile (other process running?)\n");
ftruncate($fp,0);
fwrite($fp,getmypid()) or die ('Could not write pidfile: '.$pidfile."\n");
// Prepare parameters
$params = Yii::app()->params;
$period = $params['monitor.period'];
$max = $params['monitor.max'];.
$forever= $max==0;
// Continue forever or $max times
while($forever || ($max--!==0))
{
//
// Monitor logic goes here...
//
// Sleep som time
sleep($period);
// Flush logs to keep memory footprint small
Yii::getLogger()->flush();
}
flock($fp, LOCK_UN);
fclose($fp);
}
}
I can start this "daemon" from an admin page. The code to start is like this:
private function startDaemon()
{
$started=false;
$command=Yii::getPathOfAlias('application.yiic').' daemon';
// echo $! will output the PID
exec($command.' > /dev/null 2>&1 & echo $!',$output);
// Wait 1 sec and check that the process is still running
$pid=isset($output[0]) ? (int) $output[0] : -1;
sleep(1);
exec('ps -p '.$pid,$op);
if (isset($op[1])) {
YII_DEBUG && Yii::trace('Started daemon script with PID '.$pid,'application.monitor');
return true;
} else {
YII_DEBUG && Yii::trace('Could not start daemon script! Check write permissions.','application.monitor');
return false;
}
}
You see, it’s not very sophisticated and misses lots of features. PEAR daemon would have been the better option, i guess.