微擎 生成二维码&下载二维码

新建一个类文件code.php

load()->library('qrcode');
class code{
    //生成二维码
    //参数: $content:二维码的内容 string
    //      $size:二维码的尺寸  string
    public function createCode($content,$size){        
            $errorCorrectionLevel = "L";//错误校正级别        
            $code = QRcode::png($content, false, $errorCorrectionLevel,$size);
            return $code;
    }
    //下载二维码
    //参数:二维码的内容数据content 大小size 
    public function downloadCode($content,$size){
        $code = $this->createCode($content,$size);
        $name = random(8);
        header('cache-control:private');
        header('content-type:image/jpeg');
        header('content-disposition: attachment;filename="'.$name.'.jpg"');
        readfile($code);
    }
}

在需要用到此方法的地方实例化。(注意文件的路径问题,避免实例化出错)

$code = new code();
$res_code = $code ->createCode("这里放的是二维码的内容","5");//生成二维码
$download_code = $code ->downloadCode("这里是二维码的内容","5");//下载二维码

配置码云git自动更新的webhook

配置项目提交到git的时候自动同步服务器代码

一、在服务器项目跟目录新建文件hook.php 代码如下:

<?php
$json = file_get_contents("php://input");
$data = json_decode($json,true);
if (isset($data['ref']) && $data['total_commits_count']>0) {
    $res = PHP_EOL."pull start ——————————————————————".PHP_EOL;
    $res .= shell_exec("cd /home/www/leokim && git pull https://xxxxxx.com:passwod@gitee.com/xxxx/xxxx.git 2<&1 ");
    $res_log = '——————————————————————————————'.PHP_EOL;
    $res_log .= $data['user_name'] . ' 在' . date('Y-m-d H:i:s') . '向' . $data['repository']['name'] . '项目的' . $data['ref'] . '分支push了' . $data['total_commits_count'] . '个commit:'.$data['commits']['message'];
    $res_log .= $res.PHP_EOL;
    $res_log .= "pull end ——————————————————————————".PHP_EOL;
    file_put_contents("/home/wwwlogs/webhook/".date('Y-m-d',time()).".txt", $res_log, FILE_APPEND);//写入日志到log文件中
}
?>

二、配置码云webhook:

545324-20180927103508565-515404566.png

三、确认服务器安装了git,在web目录下clone 项目:git clone https://gitee.com/xxxx/xxxx.git;

四、把git的目录权限改为web用户权限: chown -r www:www

五、手动更新代码:cd /home/www/leokim && git pull;

六、git pull 冲突或错误时,用命令git stash && git pull解决冲突或错误

微信公众号分享带参数 jsapi

<script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script>
      wx.config({
	debug: false,
        appId: 'wx9ed037f2aa8cf874',
        timestamp: '1557912019',
        nonceStr: 'nYNXxukNqGeZwVGZ',
        signature: '1053c3326a13152503cdbe04398b01a11aec6f09',
        jsApiList: [
            "onMenuShareTimeline",
            "onMenuShareAppMessage",
            "onMenuShareQQ",
            "onMenuShareQZone",
        ]
      });
      wx.ready(function () {
        // 在这里调用 API
        wx.checkJsApi({
        jsApiList: ["onMenuShareTimeline",
            "onMenuShareAppMessage",
            "onMenuShareQQ",
            "onMenuShareWeibo",
            "onMenuShareQZone",], // 需要检测的JS接口列表,所有JS接口列表见附录2,
            success: function(res) {
                if(res.errMsg !='checkJsApi:ok'){
                    alert('请升级您的微信版本');
                    return;
                }
            }
        });
      //分享Demo
      //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
      wx.onMenuShareTimeline({
        title: 'xxxxx', // 分享标题
        link: 'http://www.xxxxxx.com/mobile', // 分享链接
        imgUrl: '', // 分享图标
        success: function () { 
            // 用户确认分享后执行的回调函数
        },
        cancel: function () { 
            // 用户取消分享后执行的回调函数
        }
      });
      //获取“分享给朋友”按钮点击状态及自定义分享内容接口
      wx.onMenuShareAppMessage({
        title: '乡惠农品', // 分享标题
        desc: '乡惠农品', // 分享描述
        link: 'http://www.xxxxxxxx.com/mobile', // 分享链接
        imgUrl: '', // 分享图标
        type: '', // 分享类型,music、video或link,不填默认为link
        dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
        success: function () { 
            // 用户确认分享后执行的回调函数
        },
        cancel: function () { 
            // 用户取消分享后执行的回调函数
        }
      });
      //获取“分享到QQ”按钮点击状态及自定义分享内容接口
      wx.onMenuShareQQ({
        title: 'XXXXX', // 分享标题
        desc: 'XXXXX', // 分享描述
        link: 'http://www.XXXXX.com/mobile', // 分享链接
        imgUrl: '', // 分享图标
        success: function () { 
           // 用户确认分享后执行的回调函数
        },
        cancel: function () { 
           // 用户取消分享后执行的回调函数
        }
      });
      //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口
      wx.onMenuShareQZone({
        title: 'xxxxxx', // 分享标题
        desc: 'xxxxxxx', // 分享描述
        link: '', // 分享链接
        imgUrl: '', // 分享图标
        success: function () { 
           // 用户确认分享后执行的回调函数
        },
        cancel: function () { 
            // 用户取消分享后执行的回调函数
        }
      });
	  });
	        
</script>

Laravel 中大型项目构架

初学者学习Laravel时分两种,一种是乖乖的将程序填入MVC构架内,导致controller与model异常的肥大,日后一样很难维护;一种是常常不知道程序该写在哪一个class内而犹豫不决,毕竟传统PHP都是一个页面一个档案。本文整理出最适合Laravel的中大型项目构架,兼具容易维护、容易扩充与容易重复使用的特点,并且容易测试。

Controller过于肥大

受RoR的影响,初学者常认为MVC构架就是model,view,controller:

Model就是数据库。

Controller负责与HTTP沟通,调用model与view。

View就是HTML。

假如依照这个定义,以下这些需求该写在哪里呢?

发送Email,使用外部API。

使用PHP写的逻辑。

依需求将显示格式作转换。

依需求是否显示某些数据。

依需求显示不同数据。

其中1,2属于商业逻辑,而3,4,5属于显示逻辑,若依照一般人对MVC的定义,model是数据库,而view又是HTML,以上这些需求都不能写在model与view,只能勉强写在controller。

因此初学者开始将大量程序写在controller,造成controller的肥大难以维护。

Model过于肥大

既然逻辑写在controller不方便维护,那我将逻辑都写在model就好了?

当你将逻辑从controller搬到model后,虽然controller变瘦了,但却肥了model,model从原本代表数据库,现在变成还要负担商业逻辑与显示逻辑,结果更惨。

Model代表数据库吗?把它想成是Eloquent class就好,数据库逻辑应该写在repository里,这也是为什么Laravel 5已经没有models目录,Eloquent class仅仅是放在app根目录下而已。

中大型项目构架

那我们该怎么写呢?别将我们的思维局限在MVC内:

Model:仅当成Eloquent class。

Repository:辅助model,处理数据库逻辑,然后注入到service。

Service:辅助controller,处理商业逻辑,然后注入到controller。

Controller:接收HTTP request,调用其他service。

Presenter:处理显示逻辑,然后注入到view。

View:使用blade将数据binding到HTML。

5a426dd9e6cc9.png

其中蓝色为原本的MVC,而紫色为本文要介绍的的重点:Repository模式,Service模式与Presenter模式。

箭头表示物件依赖注入的方向。

我们可以发现MVC构架还在,由于SOLID的单一职责原则与依赖反转原则:

我们将数据库逻辑从model分离出来,由repository辅助model,将model依赖注入进repository。

我们将商业逻辑从controller分离出来,由service辅助controller,将service依赖注入进controller。

我们将显示逻辑从view分离出来,由presenter辅助view,将presenter依赖注入进view。

建立目录

在 app 目录建立 Repositories,Services 与 Presenters 目录。

image.png

别害怕在Laravel预设目录以外建立的其他目录,根据SOLID的单一职责原则,class功能越多,责任也越多,因此越违反单一职责原则,所以你应该将你的程序分割成更小的部分,每个部分都有它专属的功能,而不是一个class功能包山包海,也就是所谓的万能类别,所以整个项目不应该只有MVC三个部分,放手根据你的需求建立适当的目录,并将适当的class放到该目录下,只要我们的class有namespace帮我们分类即可。

Repository

由于篇幅的关系,将repository独立成专文讨论,请参考如何使用Repository模式?、

由于篇幅的关系,将service独立成专文讨论,请参考如何使用Service模式?

由于篇幅的关系,将presenter独立成专文讨论,请参考如何使用Presenter模式?

由于现在model、view、controller的相依物件都已经拆开,也都使用依赖注入,因此每个部分都可以单独的做单元测试,如要测试service,就将repository加以mock,也可以将其他service加以mock。

Presenter也可以单独跑单元测试,将其他service加以mock,不一定要跑验收测试才能测显示逻辑。

Conclusion

本文谈到的构架只是开始,你可以依照实际需求增加更多的目录与class,当你发现你的MVC违反SOLID原则时,就大胆的将class从MVC拆开重构,然后依照以下手法:

建立新的class或interface。

将相依物件依赖注入到class。

在class内处理他的职责。

将class或interface注入到controller或view。

最后搭配单元测试,测试重构后的构架是否与原来的需求结果相同。

如何使用mamp的php版本作为控制台的php版本

把mac上的默认php修改为MAMP等扩展环境中的php 版本,也就是不使用 mac 自带的。步骤如下:

打开terminal。输入locate .bash_profile, 找到我们需要编辑的文件的路径。

cd 到该目录下执行sudo vim .bash_profile,这个文件也有可能没有,如果没有就新建一个。

在vim中打开或新建好该文件后在文件末尾添加

export PATH="/Applications/MAMP/bin/php/php5.6.10/bin:$PATH"

注:“=”号之后,“:”号之前的路径就是你要修改成的php的路径,我这里选取的是MAMP中自带的5.6版本。

保存后运行: source .bash_profile,可能会报错,不用管。

就大功告成了,接着我们验证一下,另开terminal,输入which PHP,有没有发现默认php的路径已经修改好了呢。接下来就可以正常使用了,如果还不行,重启电脑就可以了。

坑:在 /etc/profiles 中设置了环境变量后, 还是不能在 zsh 中使用. 是因为没有在 .zshrc 中配置.

在终端中输入: cat ~/.zshrc 以此来查看 .zshrc 文件, 找到里面的 # User configuration 部分. 可以看到当前 zsh 支持的所有本地已配置环境变量.

在 export PATH=”XXXX” 里面追加一条想要配置的环境变量路径.

git pull

git -c diff.mnemonicprefix=false -c core.quotepath=false fetch origin

git -c diff.mnemonicprefix=false -c core.quotepath=false pull --no-commit origin master

laravel 递归循环子类

public function get_children_cate($parent_id){
        $childrens_arr = array();

        //check have children
        $children_cnt = DB::table('pms_product_category')->where('parentId', $parent_id)->count();
        if($children_cnt > 0){
            //get children by parent ids
            $childrens = DB::table('pms_product_category')->where('parentId', $parent_id)->get()->toArray();
            foreach($childrens as $row){
                $children = $this->get_children_cate($row->id);
                if(!empty($
                    $row->children = $children;
                }

                $childrens_arr[] = $row;
            }
        }

        return json_decode(json_encode($childrens_arr), true);
    }