YII2 – application 应用主体

在yii的入口脚本中我们可以看到如下代码:

(new yii\web\Application($config))->run();

从这里开始应用初始化,当然,除了web的应用,还有console的application

yii\console\Application。

那么,我们做一个功能的时候如何区分当前是web还是console呢?

可以通过如下的方法:

if(\Yii::$app instanceof  \yii\web\Application){

}else if(\Yii::$app instanceof  \yii\console\Application){

}

 

通过如上代码可以辨别应用属于哪个应用

yii2 cron job 插件使用

1.当我们的系统比较庞大,有很多脚本的时候,如果都写到crontab中会比较大,而且在程序方面不是很友好,现在介绍的是在程序中实现cron

插件的地址为:https://github.com/DenisOgr/yii2-cronjobs

安装:

composer  --prefer-dist denisogr/yii2-cronjobs "dev-master"

2配置:

在console/config/bootstrap.php中加入配置:设置别名

<?php
Yii::setAlias('@runnerScript', dirname(dirname(dirname(__FILE__))) .'/yii');

在console/config/main.php中加入配置:设置cron的controller

'controllerMap' => [
       'cron' => [
           'class' => 'denisog\cronjobs\CronController'
       ],
   ],

加完配置后的main.php文件如下:

<?php
$params = array_merge(
    require(__DIR__ . '/../../common/config/params.php'),
    require(__DIR__ . '/../../common/config/params-local.php'),
    require(__DIR__ . '/params.php'),
    require(__DIR__ . '/params-local.php')
);

return [
    'id' => 'app-console',
    'basePath' => dirname(__DIR__),
    'bootstrap' => ['log'],
    'controllerNamespace' => 'console\controllers',
    'components' => [
        //'log' => [
        //    'targets' => [
        //        [
        //            'class' => 'yii\log\FileTarget',
        //            'levels' => ['error', 'warning'],
        //        ],
        //    ],
       // ],
  
  'errorHandler' => [
//           'maxSourceLines' => 30,

        ],
    ],

'controllerMap' => [
       'cron' => [
           'class' => 'denisog\cronjobs\CronController'
       ],
   ],
    'params' => $params,
];

3.配置log,这个是为了输出cron整体的log

\common\config\main.php组件中加入log的配置:也即是配置log categories:cron_controller_logs

'log' =>[
      # 追踪级别
      # 消息跟踪级别
      # 在开发的时候,通常希望看到每个日志消息来自哪里。这个是能够被实现的,通过配置 log 组件的 yii\log\Dispatcher::traceLevel 属性, 就像下面这样:
      'traceLevel' => YII_DEBUG ? 3 : 0,
      
      # 通过 yii\log\Logger 对象,日志消息被保存在一个数组里。为了这个数组的内存消耗, 当数组积累了一定数量的日志消息,日志对象每次都将刷新被记录的消息到 log targets 中。 你可以通过配置 log 组件的 yii\log\Dispatcher::flushInterval 属性来自定义数量
      'flushInterval' => 1,
      
            'targets' => [
                'file1' =>[
          //'levels' => ['warning'],

          'categories' => ['cron_controller_logs'],
                    'class' => 'yii\log\FileTarget',
          
          # 当 yii\log\Logger 对象刷新日志消息到 log targets 的时候,它们并 不能立即获取导出的消息。相反,消息导出仅仅在一个日志目标累积了一定数量的过滤消息的时候才会发生。你可以通过配置 个别的 log targets 的 yii\log\Target::exportInterval 属性来 自定义这个数量,就像下面这样:
                    'exportInterval' => 1,
          # 输出文件
          'logFile' => '@app/runtime/logs/cron_controller_logs.log',
          
          # 你可以通过配置 yii\log\Target::prefix 的属性来自定义格式,这个属性是一个PHP可调用体返回的自定义消息前缀
          'prefix' => function ($message) {
            
            return $message;
          },
          # 除了消息前缀以外,日志目标也可以追加一些上下文信息到每组日志消息中。 默认情况下,这些全局的PHP变量的值被包含在:$_GET, $_POST, $_FILES, $_COOKIE,$_SESSION 和 $_SERVER 中。 你可以通过配置 yii\log\Target::logVars 属性适应这个行为,这个属性是你想要通过日志目标包含的全局变量名称。 举个例子,下面的日志目标配置指明了只有 $_SERVER 变量的值将被追加到日志消息中。
          # 你可以将 logVars 配置成一个空数组来完全禁止上下文信息包含。或者假如你想要实现你自己提供上下文信息的方式, 你可以重写 yii\log\Target::getContextMessage() 方法。
           'logVars' => [],
                ],
        
            ],
        ],

创建log文件,设置写权限  :

touch console/runtime/logs/cron_controller_logs.log
chmod 777 console/runtime/logs/cron_controller_logs.log

4.我们就要开始添加我们的cron任务了

在console/config/params.php中加入配置:

'cronJobs' =>[
        'test/example1' => [
            'cron'      => '* * * * *', 
      'cron-stdout'=> '/tmp/ExampleCommand.log',
      'cron-stderr'=> '/tmp/ExampleCommandError.log',			
        ],
    'test/example2' => [
            'cron'      => '10 * * * *',            
        ],

    ],

更详细的规则参看:

https://github.com/Yiivgeny/Yii-PHPDocCrontab/blob/master/examples/ExampleRuCommand.php

 

也就是加入了两个cron任务,一个是test/example1 这个任务是每分钟执行一次,这个任务的输出文件为cron-stdout对应的log文件,错误输出文件为cron-stderr对应的log文件。  另外一个任务是  test/example2

下面我们需要创建log文件:

touch  /tmp/ExampleCommand.log
touch /tmp/ExampleCommandError.log
chmod 777  /tmp/ExampleCommand.log
chmod 777  /tmp/ExampleCommandError.log

然后创建controller:

<?php
namespace console\controllers;
use Yii;
use yii\console\Controller;

class TestController extends Controller
{

   public function actionExample11(){
                echo 1;exit;

        }



}

然后执行:

./yii cron/run
tail -f /tmp/ExampleCommandError.log

可以看到错误输出

Error: Unknown command "test/example1".

因为上面我们的controller的action是actionExample11  ,两个1,去掉一个,在执行

vim /tmp/ExampleCommand.log

 

可以看到文件内容如下:

1

由于这个插件默认是覆盖写,所以需要修改一下:

170行附近的代码:

$command =
           $this->interpreterPath.' '.
           $command.
           $concat . escapeshellarg($stdout).
           ' 2>'.(($stdout === $stderr)?'&1':escapeshellarg($stderr));
       if ($this->isWindowsOS()){

改成:

$command =
           $this->interpreterPath.' '.
           $command.
           $concat . escapeshellarg($stdout).
           ' 2>>'.(($stdout === $stderr)?'&1':escapeshellarg($stderr));
       if ($this->isWindowsOS()){

30行左右的代码:

public $updateLogFile = false;

改为:

public $updateLogFile = true;

 

这就就可以覆盖写了,修改后的CronController.php文件内容如下:

<?php
/**
 * User: Denis Porplenko <denis.porplenko@gmail.com>
 * Date: 16.07.14
 * Time: 14:51
 */
namespace denisog\cronjobs;
use Yii;
use yii\console\Controller;
use yii\console\Exception;
class CronController extends Controller {
    const CATEGORY_LOGS = 'cron_controller_logs';
    /**
     * @var string PHPDoc tag prefix for using by PHPDocCrontab extension.
     */
    public $tagPrefix = 'cron';
    /**
     * @var string PHP interpriter path (if empty, path will be checked automaticly)
     */
    public $interpreterPath = null;
    /**
     * @var string path to writing logs
     */
    public $logsDir = null;
    /**
     * Update or rewrite log file
     * False - rewrite True - update(add to end logs)
     * @var bool
     */
    public $updateLogFile = true;
    /**
     * Placeholders:
     *     %L - logsDir path
     *     %C - name of command
     *     %A - name of action
     *     %P - pid of runner-script (current)
     *     %D(string formatted as arg of date() function) - formatted date
     * @var string mask log file name
     */
    public $logFileName = '%L/%C.%A.log';
    /**
     * @var string Bootstrap script path (if empty, current command runner will be used)
     */
    public $bootstrapScript = null;
    /**
     * @var string Timestamp used as current datetime
     * @see http://php.net/manual/en/function.strtotime.php
     */
    public $timestamp = 'now';
    /**
     * @var string the name of the default action. Defaults to 'run'.
     */
    public $defaultAction = 'run';
    /**
     * Initialize empty config parameters.
     */
    public function init() {
        parent::init();
        //Checking PHP interpriter path
        if ($this->interpreterPath === null){
            if ($this->isWindowsOS()){
                //Windows OS
                $this->interpreterPath = 'php.exe';
            }
            else{
                //nix based OS
                $this->interpreterPath = '/usr/bin/env php';
            }
        }
        //Checking logs directory
        if ($this->logsDir === null){
            $this->logsDir = Yii::$app->getRuntimePath();
        }
        //Checking bootstrap script
        if ($this->bootstrapScript === null){
            $this->bootstrapScript = Yii::getAlias('@runnerScript');
        }
    }
    /**
     * Provides the command description.
     * @return string the command description.
     */
    public function getHelp() {
        $commandUsage = Yii::getAlias('@runnerScript').' '.$this->getName();
        return <<<RAW
Usage: {$commandUsage} <action>
Actions:
    view <tags> - Show active tasks, specified by tags.
    run <options> <tags> - Run suitable tasks, specified by tags (default action).
    help - Show this help.
Tags:
    [tag1] [tag2] [...] [tagN] - List of tags
Options:
    [--tagPrefix=value]
    [--interpreterPath=value]
    [--logsDir=value]
    [--logFileName=value]
    [--bootstrapScript=value]
    [--timestamp=value]
RAW;
    }
    /**
     * Transform string datetime expressions to array sets
     *
     * @param array $parameters
     * @return array
     */
    protected function transformDatePieces(array $parameters){
        $dimensions = array(
            array(0,59), //Minutes
            array(0,23), //Hours
            array(1,31), //Days
            array(1,12), //Months
            array(0,6),  //Weekdays
        );
        foreach ($parameters AS $n => &$repeat) {
            list($repeat, $every) = explode('\\', $repeat, 2) + array(false, 1);
            if ($repeat === '*') $repeat = range($dimensions[$n][0], $dimensions[$n][1]);
            else {
                $repeatPiece = array();
                foreach (explode(',', $repeat) as $piece) {
                    $piece = explode('-', $piece, 2);
                    if (count($piece) === 2) $repeatPiece = array_merge($repeatPiece, range($piece[0], $piece[1]));
                    else                     $repeatPiece[] = $piece[0];
                }
                $repeat = $repeatPiece;
            }
            if ($every > 1) foreach ($repeat AS $key => $piece){
                if ($piece%$every !== 0) unset($repeat[$key]);
            }
        }
        return $parameters;
    }
    /**
     * Parsing and filtering PHPDoc comments.
     *
     * @param string $comment Raw PHPDoc comment
     * @return array List of valid tags
     */
    protected function parseDocComment($comment){
        if (empty($comment)) return array();
        //Forming pattern based on $this->tagPrefix
        $pattern = '#^\s*\*\s+@('.$this->tagPrefix.'(-(\w+))?)\s*(.*?)\s*$#im';
        //Miss tags:
        //cron, cron-tags, cron-args, cron-strout, cron-stderr
        if (preg_match_all($pattern, $comment, $matches, PREG_SET_ORDER)){
            foreach ($matches AS $match) $return[$match[3]?$match[3]:0] = $match[4];
            if (isset($return[0])){
                $return['_raw'] = preg_split('#\s+#', $return[0], 5);
                $return[0] = $this->transformDatePieces($return['_raw']);
                //Getting tag list. If empty, string "default" will be used.
                $return['tags'] = isset($return['tags'])?preg_split('#\W+#', $return['tags']):array('default');
                return $return;
            }
        }
    }
    /**
     * OS-independent background command execution .
     *
     * @param string $command
     * @param string $stdout path to file for writing stdout
     * @param string $stderr path to file for writing stderr
     */
    protected function runCommandBackground($command, $stdout, $stderr){
        $concat = ($this->updateLogFile) ? ' >>' : ' >';
        $command =
            $this->interpreterPath.' '.
            $command.
            $concat . escapeshellarg($stdout).
            ' 2>>'.(($stdout === $stderr)?'&1':escapeshellarg($stderr));
        if ($this->isWindowsOS()){
            //Windows OS
            pclose(popen('start /B "Yii run command" '.$command, 'r'));
        }
        else{
            //nix based OS
            system($command.' &');
        }
    }
    /**
     * Checking is windows family OS
     *
     * @return boolean return true if script running under windows OS
     */
    protected function isWindowsOS(){
        return strncmp(PHP_OS, 'WIN', 3) === 0;
    }
    /**
     * Running actions associated with {@link PHPDocCrontab} runner and matched with timestamp.
     *
     * @param array $args List of run-tags to running actions (if empty, only "default" run-tag will be runned).
     */
    public function actionRun($args = array()){
        $tags = &$args;
        $tags[] = 'default';
        //Getting timestamp will be used as current
        $time = strtotime($this->timestamp);
        if ($time === false) throw new CException('Bad timestamp format');
        $now = explode(' ', date('i G j n w', $time));
        $runned = 0;
        foreach ($this->prepareActions() as $task) {
            if (array_intersect($tags, $task['docs']['tags'])){
                foreach ($now AS $key => $piece){
                    //Checking current datetime on timestamp piece array.
                    if (!in_array($piece, $task['docs'][0][$key])) continue 2;
                }
                //Forming command to run
                $command = $this->bootstrapScript.' '.$task['command'].'/'.$task['action'];
                if (isset($task['docs']['args'])) $command .= ' '.escapeshellcmd($task['docs']['args']);
                //Setting default stdout & stderr
                if (isset($task['docs']['stdout'])) $stdout = $task['docs']['stdout'];
                else                                $stdout = $this->logFileName;
                $stdout = $this->formatFileName($stdout, $task);
                if(!is_writable($stdout)) {
                    $stdout = '/dev/null';
                }
                $stderr = isset($task['docs']['stderr'])?$this->formatFileName($task['docs']['stderr'], $task):$stdout;
                if(!is_writable($stderr)) {
                    $stdout = '/dev/null';
                }
                $this->runCommandBackground($command, $stdout, $stderr);
                Yii::info('Running task ['.(++$runned).']: '.$task['command'].' '.$task['action'], self::CATEGORY_LOGS);
            }
        }
        if ($runned > 0){
            Yii::info('Runned '.$runned.' task(s) at '.date('r', $time), self::CATEGORY_LOGS);
        } else {
            Yii::info('No task on '.date('r', $time), self::CATEGORY_LOGS);
        }
    }
    /**
     * Show actions associated with {@link PHPDocCrontab} runner.
     *
     * @param $args array List of run-tags for filtering action list (if empty, show all).
     */
    public function actionView($args = array()){
        $tags = &$args;
        foreach ($this->prepareActions() as $task) {
            if (!$tags || array_intersect($tags, $task['docs']['tags'])){
                //Forming to using with printf function
                $times = $task['docs']['_raw'];
                array_unshift($times, $task['command'].'.'.$task['action']);
                array_unshift($times, "Action %-40s on %6s %6s %6s %6s %6s %s\n");
                array_push($times, empty($task['docs']['tags'])?'':(' ('.implode(', ', $task['docs']['tags']).')'));
                call_user_func_array('printf', $times);
            }
        }
    }
    protected function formatFileName($pattern, $task){
        $pattern = str_replace(
            array('%L', '%C', '%A', '%P'),
            array($this->logsDir, $task['command'], $task['action'], getmypid()),
            $pattern
        );
        return preg_replace_callback('#%D\((.+)\)#U', create_function('$str', 'return date($str[1]);'), $pattern);
    }
    /**
     * Help command. Show command usage.
     */
    public function actionHelp(){
        echo $this->getHelp();
    }
    /**
     * Getting tasklist.
     *
     * @return array List of command actions associated with {@link PHPDocCrontab} runner.
     */
    protected function prepareActions()
    {
        $actions = array();
        try {
            $methods = Yii::$app->params['cronJobs'];
        }catch (yii\base\ErrorException $e) {
            throw new yii\base\ErrorException('Empty param cronJobs in params. ',8);
        }
        if (!empty($methods)) {
            foreach ($methods as $runCommand => $runSettings) {
                $runCommand = explode('/', $runCommand);
                if (count($runCommand) == 2) {
                    $actions[] = array(
                        'command' => $runCommand[0],
                        'action'  => $runCommand[1],
                        'docs'    => $this->parseDocComment($this->arrayToDocComment($runSettings))
                    );
                }
                if (count($runCommand) == 3) {
                    $actions[] = array(
                        'command' => $runCommand[0] . '/' . $runCommand[1],
                        'action'  => $runCommand[2],
                        'docs'    => $this->parseDocComment($this->arrayToDocComment($runSettings))
                    );
                }
                if (count($runCommand) == 4) {
                    $actions[] = array(
                        'command' => $runCommand[0] . '/' . $runCommand[1] .  '/' . $runCommand[2],
                        'action'  => $runCommand[3],
                        'docs'    => $this->parseDocComment($this->arrayToDocComment($runSettings))
                    );
                }
                if(empty($actions)) {
                    continue;
                }
            }
        }
        return $actions;
    }
    protected function arrayToDocComment(array $runSettings)
    {
        $result = "/**\n";
        foreach ($runSettings as $key => $setting) {
            $result .= '* @' . $key . ' ' . $setting . "\n";
        }
        $result .= "*/\n";
        return $result;
    }
}

然后我们需要设置cron ,让 ./yii cron/run 可以每分钟运行。

在console/config/params.php文件配置cron

每隔2分钟运行一次

'cron'      => '*\2 * * * *',

分:每1025,26,27,28,29,3040分钟

时:每天第2(偶数)小时

天:15至21和从23至27的数

月:一月至六月,偶数月

周:不管第几周

'cron' => '10,25-30,40 *\2 15-21,23-27 1-6\2 *',

 

 

yii2 数据库版本控制 migrations

对于在日常的开发,我们用mysql,当线下分几个小组对一个网站进行开发的时候,在线下建立表,如何同步到线上就成了一个问题。

svn git等版本控制系统,可以控制文件的版本,yii2通过migrate,来进行sql文件的上传,以及执行。

migrate的使用:

1.首先创建migrate文件,语法很简单:

./yii migrate/create    test_user

执行后,就会在/console/migrations/下面生成m160511_080937_test_user.php。

下面是执行log

[root@services datacenter_1000]# ./yii migrate/create    test_user  
Yii Migration Tool (based on Yii v2.0.7)

Create new migration '/www/web/datacenter/datacenter_1000/console/migrations/m160511_080937_test_user.php'? (yes|no) [no]:yes
New migration created successfully.

默认的路径是在console/migrations下面。

如果执行 ./yii migrate   就会执行console/migrations 下面的sql,当然,在执行前,需要到表migration 中查看信息,然后在决定执行那些sql,执行的是文件中的up()方法里面的sql,如果是事务操作,则不适用up(),而使用safeUp()方法。

有时候我们有自己的扩展,然后把migration放到自己的扩展里面,可以通过加入参数–migrationPath=@yii/log/migrations

来创建,执行相应的数据库脚本、

./yii migrate --migrationPath=@yii/log/migrations/

 

同样 down() , 采用 safeDown()方法。

如下是所有这些数据库访问方法的列表:

yii\db\Migration::execute(): 执行一条 SQL 语句
yii\db\Migration::insert(): 插入单行数据
yii\db\Migration::batchInsert(): 插入多行数据
yii\db\Migration::update(): 更新数据
yii\db\Migration::delete(): 删除数据
yii\db\Migration::createTable(): 创建表
yii\db\Migration::renameTable(): 重命名表名
yii\db\Migration::dropTable(): 删除一张表
yii\db\Migration::truncateTable(): 清空表中的所有数据
yii\db\Migration::addColumn(): 加一个字段
yii\db\Migration::renameColumn(): 重命名字段名称
yii\db\Migration::dropColumn(): 删除一个字段
yii\db\Migration::alterColumn(): 修改字段
yii\db\Migration::addPrimaryKey(): 添加一个主键
yii\db\Migration::dropPrimaryKey(): 删除一个主键
yii\db\Migration::addForeignKey(): 添加一个外键
yii\db\Migration::dropForeignKey(): 删除一个外键
yii\db\Migration::createIndex(): 创建一个索引
yii\db\Migration::dropIndex(): 删除一个索引

有时,你可能只需要提交一个或者少数的几个迁移,你可以使用该命令指定需要执行的条数,而不是执行所有的可用迁移。例如,如下命令将会尝试提交前三个可用的迁移:

yii migrate 3

你也可以指定一个特定的迁移,按照如下格式使用 migrate/to 命令来指定数据库应该提交哪一个迁移:

yii migrate/to 150101_185401                      # using timestamp to specify the migration 使用时间戳来指定迁移
yii migrate/to "2015-01-01 18:54:01"              # using a string that can be parsed by strtotime() 使用一个可以被 strtotime() 解析的字符串
yii migrate/to m150101_185401_create_news_table   # using full name 使用全名
yii migrate/to 1392853618                         # using UNIX timestamp 使用 UNIX 时间戳

 

其他:来自于官网资料。

还原迁移

你可以使用如下命令来还原其中一个或多个意见被提交过的迁移:

yii migrate/down     # revert the most recently applied migration 还原最近一次提交的迁移
yii migrate/down 3   # revert the most 3 recently applied migrations 还原最近三次提交的迁移

 

重做迁移

重做迁移的意思是先还原指定的迁移,然后再次提交。如下所示:

yii migrate/redo        # redo the last applied migration 重做最近一次提交的迁移
yii migrate/redo 3      # redo the last 3 applied migrations 重做最近三次提交的迁移

 

列出迁移

你可以使用如下命令列出那些提交了的或者是还未提交的迁移:

yii migrate/history     # 显示最近10次提交的迁移
yii migrate/history 5   # 显示最近5次提交的迁移
yii migrate/history all # 显示所有已经提交过的迁移

yii migrate/new         # 显示前10个还未提交的迁移
yii migrate/new 5       # 显示前5个还未提交的迁移
yii migrate/new all     # 显示所有还未提交的迁移

 

修改迁移历史

有时候你也许需要简单的标记一下你的数据库已经升级到一个特定的迁移,而不是实际提交或者是还原迁移。这个经常会发生在你手动的改变数据库的一个特定状态,而又不想相应的迁移被重复提交。那么你可以使用如下命令来达到目的:

yii migrate/mark 150101_185401                      # 使用时间戳来指定迁移
yii migrate/mark "2015-01-01 18:54:01"              # 使用一个可以被 strtotime() 解析的字符串
yii migrate/mark m150101_185401_create_news_table   # 使用全名
yii migrate/mark 1392853618                         # 使用 UNIX 时间戳

 

 

Yii2 – 如何写一个插件 , 如何做一个扩展

1.在github申请账户,申请完成就可以创建项目了

2.创建一个composer.json文件:内容如下:

{  
  "name": "zqy234/terrytest",  
  "description": "Yii2 zqy234 terrytest",  
  "keywords": [  
    "yii2",  
    "terrytest"  
  ],  
  "homepage": "https://github.com/zqy234/terrytest",  
  "type": "yii2-extension",  
  "license": "MIT",  
  "support": {  
    "source": "https://github.com/zqy234/terrytest"  
  },  
  "authors": [  
    {  
      "name": "terry water",  
      "email": "zqy234@126.com"  
    }  
  ],  
  "minimum-stability": "stable",  
  "require": {  
    "php": ">=5.4.0",  
    "yiisoft/yii2": ">=2.0.6"  
     
  },  
  "autoload": {  
    "psr-4": {  
      "terry\\": ""  
    }  
  },  
  "config": {  
    "process-timeout": 1800  
  }  
}

我的扩展的地址为:https://github.com/zqy234/terrytest

上面的信息大致核对自己的地址填写,比较重要的为下面

2.1.require 这个是当前插件需要的库包

2.2.autoload:为在aotuload自动加载的信息,psr-4:所在部分加入自动加载的信息,当访问terry\开头的,都会到这个插件的路径下面找文件。

在插件安装的时候,上面psr-4的信息会安装到文件/vendor/composer/autoload_psr4.php 中,具体信息,可以到这个文件夹中查看详细。

3.搞完上面的,我们需要在包管理里面添加。

打开:https://packagist.org/packages/submit

把github的地址提交,提交成功后的界面:

4.到这里就提交成功了,您可以使用composer下载了:

[root@iZ942k2d5ezZ cc]# composer require  zqy234/terrytest:dev-master  
./composer.json has been updated  
Loading composer repositories with package information  
Updating dependencies (including require-dev)  
  - Installing zqy234/terrytest (dev-master c80914f)  
    Cloning c80914fc7dedc2f464f16fb0af5d3a843326bddb  
  
Writing lock file  
Generating autoload files

5.使用正式版本号(稳定版本号)

首先去github中:

然后再packagist中更新:

然后就可以更新了:

[root@iZ942k2d5ezZ cc]# composer require --prefer-dist zqy234/terrytest  
Using version ^1.0 for zqy234/terrytest  
./composer.json has been created  
Loading composer repositories with package information  
Updating dependencies (including require-dev)  
  - Installing yiisoft/yii2-composer (2.0.3)                 
    Loading from cache  
  
  - Installing bower-asset/jquery (2.1.4)  
    Loading from cache  
  
  - Installing bower-asset/yii2-pjax (v2.0.5)  
    Loading from cache  
  
  - Installing bower-asset/punycode (v1.3.2)  
    Loading from cache  
  
  - Installing bower-asset/jquery.inputmask (3.1.63)  
    Loading from cache  
  
  - Installing cebe/markdown (1.1.0)  
    Loading from cache  
  
  - Installing ezyang/htmlpurifier (v4.6.0)  
    Loading from cache  
  
  - Installing yiisoft/yii2 (2.0.6)  
    Loading from cache  
  
  - Installing zqy234/terrytest (1.0.0)  
    Downloading: 100%           
  
Writing lock file  
Generating autoload files  
[root@iZ942k2d5ezZ cc]#

这样就安装成功了。

6.版本号自动更新(github和packagist之间)

访问:https://packagist.org/profile/

获取api token

详细说明地址:https://packagist.org/about

填写的url的格式:https://packagist.org/api/bitbucket?username=USERNAME&apiToken=API_TOKEN

可以用:

curl -XPOST -H'content-type:application/json' 'https://packagist.org/api/update-package?username=USERNAME&apiToken=API_TOKEN' -d'{"repository":{"url":"PACKAGIST_PACKAGE_URL"}}'

来检测。

测试:

在github那边增加一个稳定版本号

然后再 https://packagist.org/packages/zqy234/terrytest#1.0.1

发现:1.0.1出来了。

基本的详细大致使用就这些

总之,可以快乐的,让别人下载自己的库包了

composer require --prefer-dist zqy234/terrytest

 

Yii2 安装 – composer

yii2的框架的安装,以及扩展的安装,都是用composer,下面是安装composer的具体方法:

  1. 查看php是否存在
    php --version

    如果不存在,将安装的php设置下快捷方式,这样,就可以直接用php执行。

  2. 我当前的php的安装路径为/usr/local/php/bin/php 我设置了下快捷方式:
  3. ln -s /usr/local/php/bin/php  /usr/local/bin/php
  4. 安装composer
    curl -sS https://getcomposer.org/installer | php
    mv composer.phar /usr/local/bin/composer
  5. 到这里就安装完成了,譬如,我可以用下面的方式安装asset
    composer global require "fxp/composer-asset-plugin:~1.1.1"

    上面如果报错:参看:http://stackoverflow.com/questions/36579559/updating-composer-throws-exception-class-fxp-composer-assetplugin-repository-npm

    try to update your fxp/composer-asset-plugin:

    php composer.phar global update fxp/composer-asset-plugin --no-plugins

    PS: If after update it still not working, try also following:

    composer global require fxp/composer-asset-plugin --no-plugins

    如果上面的方法还是有问题,譬如我曾经的报错:

    我采取的办法是清空composer global存放的文件夹。我的composer我使用的是root账户,我清空命令如下:

    rm -rf /root/.composer

    然后重新安装:

    composer global require "fxp/composer-asset-plugin:^1.2.0"

    文章参考:

    https://getcomposer.org/doc/03-cli.md#global

https://getcomposer.org/doc/03-cli.md#composer-home

yii2 redis 使用 unixSocket 的方式连接 以及配置

yii2 官方除了一个redis连接的扩展,默认的情况下连接redis,并不是最高效,用unixSocket的方式,速度至少提高一半,配置的方式如下:

1.配置如下:

'redis' => [  
            'class' => 'yii\redis\Connection',  
            'hostname' => 'localhost',  
            'port' => 6379,  
            'database' => 0,  
            'password'  => 'rdsFD',  
            'unixSocket' => '/tmp/redis.sock',  
        ],

也就是在unixSocket 项,配置redis.sock的路径。具体的路径,按照redis unixSocket的路径进行设置。

总之:’unixSocket’ => ‘/tmp/redis.sock’,  是配置 unix Socket的链接方式,速度要比TCP的要快一半。

2.配置redis

vim /etc/redis/6379.conf   (在redis的配置文件中进行修改。)

unixsocket /tmp/redis.sock  
unixsocketperm 700

保存,重启redis。

3.这样,redis就配置好了,使用unixSocket速度比较快一些,用默认的方式,对于一般的Yii2网站来说,也没有太多的问题。

yii2初始化详解 – 深究yii2 autoload机制

yii2采用的基于namespace的autoload机制,我们从初始化来参看yii2的autoload机制的整个过程,详解yii的初始化过程

1.在入口文件index.php我们可以看到代码:

require(__DIR__ . '/../../vendor/autoload.php');

2.我们打开这个文件:

<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';

return ComposerAutoloaderInit90def245ed1c6f870abec3fefcc03f88::getLoader();

可以看到加载了文件/vendor/composer/autoload_real.php,打开这个文件,我们可以发现,里面定义了一个php的class类:

ComposerAutoloaderInit90def245ed1c6f870abec3fefcc03f88

也就是调用了这个类的getLoader()方法。

3.找到这个方法getLoader()方法:下面是所有的代码:

<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit90def245ed1c6f870abec3fefcc03f88
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInit90def245ed1c6f870abec3fefcc03f88', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit90def245ed1c6f870abec3fefcc03f88', 'loadClassLoader'));

        $map = require __DIR__ . '/autoload_namespaces.php';
        foreach ($map as $namespace => $path) {
            $loader->set($namespace, $path);
        }

        $map = require __DIR__ . '/autoload_psr4.php';
        foreach ($map as $namespace => $path) {
            $loader->setPsr4($namespace, $path);
        }

        $classMap = require __DIR__ . '/autoload_classmap.php';
        if ($classMap) {
            $loader->addClassMap($classMap);
        }

        $loader->register(true);

        $includeFiles = require __DIR__ . '/autoload_files.php';
        foreach ($includeFiles as $file) {
            composerRequire90def245ed1c6f870abec3fefcc03f88($file);
        }

        return $loader;
    }
}

function composerRequire90def245ed1c6f870abec3fefcc03f88($file)
{
    require $file;
}

首先我们看到的是spl_autoload_register这个方法,这个方法的作用是,在找不到类的情况下,通过这个函数定义的类方法去找,通过传递的参数,返回加载的类的路径。也就是说,当找不到类的时候,就通过这个方法找:

public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

因此这段代码  self::$loader = $loader = new \Composer\Autoload\ClassLoader();

加载的文件是vendor/composer/ClassLoader.php

4.然后通过这个类的方法,加载很多初始路径:

$map = require __DIR__ . '/autoload_namespaces.php';
       foreach ($map as $namespace => $path) {
           $loader->set($namespace, $path);
       }

       $map = require __DIR__ . '/autoload_psr4.php';
       foreach ($map as $namespace => $path) {
           $loader->setPsr4($namespace, $path);
       }

       $classMap = require __DIR__ . '/autoload_classmap.php';
       if ($classMap) {
           $loader->addClassMap($classMap);
       }

       $loader->register(true);

       $includeFiles = require __DIR__ . '/autoload_files.php';
       foreach ($includeFiles as $file) {
           composerRequire90def245ed1c6f870abec3fefcc03f88($file);
       }

       return $loader;

4.1通过set  setPsr4  addClassMap等方法进行namespace路径初始化。 这个对应的文件是/autoload_psr4.php , 这个文件里面是对yii2的插件的namespace的定义:

<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'yii\\swiftmailer\\' => array($vendorDir . '/yiisoft/yii2-swiftmailer'),
    'yii\\redis\\' => array($vendorDir . '/yiisoft/yii2-redis'),
    'yii\\gii\\' => array($vendorDir . '/yiisoft/yii2-gii'),
    'yii\\faker\\' => array($vendorDir . '/yiisoft/yii2-faker'),
    'yii\\debug\\' => array($vendorDir . '/yiisoft/yii2-debug'),
    'yii\\composer\\' => array($vendorDir . '/yiisoft/yii2-composer'),
    'yii\\codeception\\' => array($vendorDir . '/yiisoft/yii2-codeception'),
    'yii\\bootstrap\\' => array($vendorDir . '/yiisoft/yii2-bootstrap'),
    'yii\\' => array($vendorDir . '/yiisoft/yii2'),
    'fecadmin\\' => array($vendorDir . '/fancyecommerce/fec_admin'),
    'fec\\' => array($vendorDir . '/fancyecommerce/fec'),
    'cebe\\markdown\\' => array($vendorDir . '/cebe/markdown'),
    'Faker\\' => array($vendorDir . '/fzaninotto/faker/src/Faker'),
);

定义各个插件的根路径。

4.2autoload_classmap.php 这个目前为空,没有细致研究具体内部的存放

4.3/autoload_files.php

<?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
    '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
);

4.4  这是非yii2插件的包库 autoload_namespaces.php

<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'PHPExcel' => array($vendorDir . '/phpoffice/phpexcel/Classes'),
    'Imagine' => array($vendorDir . '/imagine/imagine/lib'),
    'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
    'Diff' => array($vendorDir . '/phpspec/php-diff/lib'),
);

譬如我的yii2 – fec 插件中加入的PHPExcel 和Imagine 库包,就会在这里被标注namespace的对应关系。

对于composer安装的库包,有的是include的方式加入的,譬如Excel,安装库包后,不需要再程序中require,包管理器在autoload_namespaces.php  会加入路径,自动加载进来。

还有的是基于namespaces的,譬如Imagine。

5. 通过上面的配置,去找到对应文件路径,加载文件。

也就是说,对于 https://packagist.org/ 这里的php的库包,我们都可以通过composer加载到我们的系统中,在线安装。

譬如:我的fec插件的   composer.json的配置。

"require": {
      "php": ">=5.4.0",
      "yiisoft/yii2": ">=2.0.6",
      "imagine/imagine": "0.5.*",
      "phpoffice/phpexcel": "1.8.*"
},
"autoload": {
  "psr-4": {
    "fec\\": ""
  }
},

其中require代表的需要下载的包

autoload  psr-4 里面添加了信息后,会在 vendor/yiisoft/extensions.php 文件中加入别名。

'fancyecommerce/fec' =>
 array (
   'name' => 'fancyecommerce/fec',
   'version' => '1.1.2.4',
   'alias' =>
   array (
     '@fec' => $vendorDir . '/fancyecommerce/fec',
   ),
 ),

 

vendor/composer/autoload_psr4.php 中加入namespace信息:

'fecadmin\\' => array($vendorDir . '/fancyecommerce/fec_admin'),
    'fec\\' => array($vendorDir . '/fancyecommerce/fec'),

 

 

 

 

 

 

 

yii2 model 输出sql

我们在使用model进行查询的时候,或者其他,我们想要打印出来model赋值后,在mysql数据库中执行的sql,我们可以使用下面的方法打印sql。

$query = Salesorder::find()  
  ->where(['order_id'=>[1,2,3,4]])  
  ->select(['order_id'])  
;  
// get the AR raw sql in YII2  
$commandQuery = clone $query;  
echo $commandQuery->createCommand()->getRawSql();  
exit;