THINKPHP的cron计划任务的实现

写一个cli的入口文件

cli.php

<?php
define(‘MODE_NAME‘, ‘cli‘);
// 检测PHP环境
if(version_compare(PHP_VERSION,‘5.3.0‘,‘<‘))  die(‘require PHP > 5.3.0 !‘);

define(‘APP_DEBUG‘, true);

// 定义应用目录
define(‘APP_PATH‘, __DIR__ . ‘/Application/‘);

// 引入ThinkPHP入口文件
require __DIR__ . ‘/ThinkPHP/ThinkPHP.php‘;

写一个执行文件

cron.php

define(‘AUTO_CRON‘, true);
include __DIR__ . ‘/cli.php‘;

数据库设计

DROP TABLE IF EXISTS `cron`;
CREATE TABLE IF NOT EXISTS `cron` (
  `cron_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘,
  `expression` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘,
  `class` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘,
  `method` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘,
  `type` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘,
  `status` varchar(30) COLLATE utf8_unicode_ci NOT NULL DEFAULT ‘‘,
  `created_at` timestamp NOT NULL DEFAULT ‘0000-00-00 00:00:00‘,
  `updated_at` timestamp NOT NULL DEFAULT ‘0000-00-00 00:00:00‘,
  `run_at` timestamp NULL DEFAULT NULL,
  `ms` int(10) unsigned NOT NULL DEFAULT ‘0‘,
  `error` text COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`cron_id`),
  KEY `name` (`name`,`created_at`),
  KEY `cron_status_index` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;

执行文件 init.php  

/写个hook程序执行init.php

<?php
use Think\Log, Think\Db, Cron\Model\Cron;
$Model = new \Think\Model();
$Has = !$Model->query("SHOW TABLES LIKE ‘cron‘")?false:true;

if(defined("AUTO_CRON") && $Has){
    class CronCommand
    {

        protected $_initializedJobs;
        protected $_jobs;
        protected $_now;

        public function __construct()
        {
            $this->_now = strtotime(date(‘Y-n-j H:i‘));
            import("Cron.Common.Cron.tdcron_entry",‘‘,‘.php‘);
            import("Cron.Common.Cron.tdcron",‘‘,‘.php‘);
        }

        /**
         * 这里是放要执行的代码
         */
        public function fire()
        {
            restore_error_handler();
            restore_exception_handler();
            $this->_initializedJobs = array();
            $jobs = M(‘cron‘)->where("status = ‘initialized‘")->select();
            /**
             * @var $cron Cron
             * 已存在 cron
             */
            if($jobs) {
                $cron = new Cron();
                foreach ($jobs as $data) {
                    $cron->setData($data)->isNew(false);
                    $this->_initializedJobs[$data[‘name‘]] = $cron;
                }
            }

            /**
             * 新 cron
             */
            foreach ($this->getCronJobs() as $name => $cronJob) {
                if (isset($cronJob[‘expression‘])) {
                    $expression = $cronJob[‘expression‘];
                } else {
                    Log::write(‘Cron expression is required for cron job "‘ . $name . ‘"‘,Log::WARN);
                    continue;
                }
                if ($this->_now != tdCron::getNextOccurrence($expression, $this->_now)) continue;
                $cronJob[‘name‘] = $name;
                $cron = isset($this->_initializedJobs[$name]) ? $this->_initializedJobs[$name] : $this->_initializedJobs[$name] = new Cron();
                $cron->initialize($cronJob);
            }

            /* @var $cron Cron 处理*/
            foreach ($this->_initializedJobs as $cron) {
                $cron->run();
            }

        }


        /**
         * Get All Defined Cron Jobs
         * 获取配置
         * @return array
         */
        public function getCronJobs()
        {
            if ($this->_jobs === null) {
                $this->_jobs = C(‘beastalkd‘);
            }
            return $this->_jobs;
        }

    }
    $command = new CronCommand();
    $command->fire();
}

cron 模型

<?php
namespace Cron\Model;
use Common\Model;
use Think\Log;

/**
 * Class Cron
 * @method string getClass()
 * @method string getMethod()
 * @method string getName()
 * @method string getType()
 * @package Cron\Model
 */
class Cron extends Model{

    const STATUS_COMPLETED = ‘completed‘;
    const STATUS_FAILED = ‘failed‘;
    const STATUS_INITIALIZED = ‘initialized‘;
    const STATUS_RUNNING = ‘running‘;

    protected $name = ‘cron‘;
    protected $tableName = ‘cron‘;
    protected $pk = ‘cron_id‘;

    protected $_originalData = array();
    /**
     *  保存配置信息CLASS
     */
    protected static $_cron_classes = array();


    /**
     * @param $class
     * @return mixed  获取配置的 CLASS
     */
    public function getSingleton($class)
    {
        isset(static::$_cron_classes[$class]) or static::$_cron_classes[$class] = new $class;
        return static::$_cron_classes[$class];
    }


    /**
     * @param $cronJob
     * @return $this
     * 初始化 任务状态
     */
    public function initialize($cronJob)
    {
        foreach ($cronJob as $k => $v) {
            $this->setData($k, $v);
        }
        $now = date(‘Y-m-d H:i:s‘);
        $this->setData(‘status‘,self::STATUS_INITIALIZED)->setData(‘created_at‘,$now)->setData(‘updated_at‘,$now)->save();
        return $this;
    }

    /**
     * @return $this  run 命令
     */
    public function run()
    {
        $this->setData(‘run_at‘,date(‘Y-m-d H:i:s‘))->setData(‘status‘,self::STATUS_RUNNING)->save();
        Timer::start();
        try {
            $class = $this->getData(‘class‘);
            $method = $this->getData(‘method‘);
            if (!class_exists($class)) throw new \Exception(sprintf(‘Class "%s" not found!‘, $class));
            if (!method_exists($class, $method)) throw new \Exception(sprintf(‘Method "%s::%s()" not found!‘, $class, $method));
            $callback = array($this->getSingleton($class), $method);

            //new CLASS 使用操作方法
            call_user_func($callback);
            Timer::stop();
            $this->setData(‘ms‘,round(Timer::diff() * 1000))->setData(‘status‘,self::STATUS_COMPLETED)->save();

        } catch (\Exception $e) {
            Timer::stop();
            $this->setData(‘ms‘,round(Timer::diff() * 1000))
                ->setData(‘status‘,self::STATUS_FAILED)
                ->setData(‘error‘,$e->getMessage() . "\nParams:\n" . var_export($this->getDbFields(), true))->save();
            Log::write($e->getMessage() . "\n" . $e->getTraceAsString(),Log::ERR);
        }
        return $this;
    }

}

Common\Model 模型

<?php

namespace Common;

use Think\Model as ThinkModel;

/**
 * Class Model
 * @package Common
 *
 * @property \Think\Db\Driver\Mysql $db DB instance
 */
abstract class Model extends ThinkModel {
   protected $_isNew = true;
   protected $_jsonFields = array();
   protected $_originalData = array();

   protected function _after_find(&$result, $options) {
      foreach ($this->_jsonFields as $field) {
         is_string($_data = fnGet($result, $field)) and $result[$field] = json_decode($_data, true);
      }
      $this->_originalData = $result;
      $this->_isNew = !$result;
      parent::_after_find($result, $options);
   }

   protected function _after_save($result) {
   }

   protected function _before_find() {
      $this->_originalData = array();
   }

   protected function _facade($data) {
      foreach ($this->_jsonFields as $field) {
         is_array($_data = fnGet($data, $field)) and $data[$field] = json_encode($_data);
      }
      return parent::_facade($data);
   }

   public function find($options = array()) {
      $this->_before_find();
      return parent::find($options);
   }

   public function getData($key = null) {
      return $key === null ? $this->data : $this->__get($key);
   }

   public function getOptions() {
      return $this->options;
   }

   public function getOriginalData($key = null) {
      return $key === null ? $this->_originalData : fnGet($this->_originalData, $key);
   }

   /**
    * Get or set isNew flag
    *
    * @param bool $flag
    *
    * @return bool
    */
   public function isNew($flag = null) {
      if ($flag !== null) $this->_isNew = (bool)$flag;
      return $this->_isNew;
   }

   public function save($data = ‘‘, $options = array()) {
      if ($this->_isNew) {
         $oldData = $this->data;
         $result = $this->add($data, $options);
         $this->data = $oldData;
         if ($result && $this->pk && is_string($this->pk)) {
            $this->setData($this->pk, $result);
         }
         $this->_isNew = false;
      } else {
         $oldData = $this->data;
         $result = parent::save($data, $options);
         $this->data = $oldData;
      }
      $this->_after_save($result);
      return $result;
   }

   public function setData($key, $value = null) {
      is_array($key) ?
         $this->data = $key :
         $this->data[$key] = $value;
      return $this;
   }
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。