关于laravel:Laravel数据库常用方法获取结果

1.获得数据表的所有行你能够应用 DB facade 里的 table 办法来开始查问。 table 办法为给定的表返回一个查问结构器实例,容许你在查问上链式调用更多的束缚,最初应用 get 办法获取后果:namespace App\Http\Controllers;use App\Http\Controllers\Controller;use Illuminate\Support\Facades\DB;class UserController extends Controller{ // 显示所有应用程序的用户列表。 public function index() { $users = DB::table('users')->get(); }}get() 办法返回一个蕴含 IlluminateSupportCollection 的后果,其中每个后果都是 PHP StdClass 对象的一个实例。能够用 toArray() 把对象转数组。2.从数据表中获取单行如果只须要从数据表中获取一行数据,应用 first 办法。该办法返回一个 StdClass 对象:$user = DB::table('users')->where('name', 'John')->first();dd($user->name);通过 id 字段值获取一行数据,应用 find 办法:$user = DB::table('users')->find(1);3.从数据表中获取单列如果只须要从数据表中获取一行数据,应用 first 办法。该办法返回一个 StdClass 对象:$nameItems = DB::table('users')->pluck('name');foreach ($nameItems as $name) { echo $name;}4.从数据表中获取单个值如果只须要从数据表中获取一行数据,应用 first 办法。该办法返回一个 StdClass 对象:$addr = DB::table('users')->where('name', 'John')->value('addr');

July 29, 2020 · 1 min · jiezi

关于laravel:构造一个仿Laravel-Mvc框架-模型Model

接上篇 结构一个仿Laravel Mvc框架 - 路由篇,本章接着叙述,如何构建框架中的 Model层(模型)。 上一篇中的案例都是将代码写在路由闭包中的,如果路由定义的多了,十分不好保护和治理.所以咱们首先须要实现一个 Controller 来解决咱们的业务逻辑,也就是Mvc中的C层。 建设控制器首先参考Laravel目录架构,创立好咱们的控制器文件 mkdir App/Http/Controllers/IndexControllerIndexController创立实现后,编写相干的函数来解决首页的逻辑. <?phpnamespace App\Http\Controllers;class IndexController{ public function index() { return '胜利拜访首页,这里是IndexController'; }}更改路由映射到该控制器上,批改routers.php $app['router']->get('/index', 'App\Http\Controllers\IndexController@index');最初更改composer.json,配置主动加载门路,而后再执行 composer dump-autoload { "name": "17ns/laramvc", "authors": [{ "name": "17ns", "email": "aa@bb.com" }], "require": { "illuminate/routing": "*", "illuminate/events": "*" }, "autoload": { "psr-4": { "App\\": "app/" } }}增加模型组件下面步骤实现实现后,就开始增加 illuminate/database 这个组件,来实现像Laravel一样的弱小的ORM。 执行上面的命令开始引入组件 composer require "illuminate/database":"*" 引入实现后,就开始欠缺数据库的配置,这里仍然参照laravel建设一个 config/database.php 文件,来作为数据库连贯的配置文件,建设实现后,开始填写本地货远端服务器的MYSQL配置信息。 <?phpreturn [ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'laramvc', 'username' => 'root', 'password' => 'localdb001', 'charset' => 'utf8', 'collation' => 'utf8_general_ci', 'prefix' => '',];配置实现后,就须要在首页入口文件启动 Eloquent ORM,相干代码如下: ...

July 27, 2020 · 1 min · jiezi

关于laravel:mPDF-临时文件目录不可写

1.问题还原Temporary files directory "……/vendor/mpdf/mpdf/src/Config/../../tmp" is not writable2.解决方案本地开发windows环境并没有呈现问题,部署到Linux服务器,呈现长期文件目录...不可写。百度了很多没有找到解决方案,最初浏览官网文档,尝试在对象初始化时指定长期目录,就OK了。$mpdf = new \Mpdf\Mpdf([ 'tempDir' => __DIR__ . '/tmp']);

July 21, 2020 · 1 min · jiezi

关于laravel:构造一个仿Laravel-Mvc框架-路由篇

在咱们日常应用Laravel框架中,有很多值得咱们学习的设计理念和开发思维,如何代码变得更加“优雅”,外围架构中组件化、服务容器、数据库ORM 都是很值得咱们去探索一二的方向。 在本系列博客中,将利用 Laravel 中组件化的特点来构建一个迷你 仿 Laravel 的 MVC框架。 本篇的利用次要是讲述,如何利用 illuminate/routing 来实现框架的路由模块,通过配置的定义来实现申请的转发和跳转。 1.初始化一个新我的项目首先创立一个我的项目,名称轻易定义,我这里采纳的是 laramvc mkdir laramvc而后创立一个 composer.json 文件 填充内容如下: { "name": "你的项目名称", "authors": [{ "name": "作者名称", "email": "作者邮箱" }], "require": { }}执行 composer update 用于生成vendor目录及主动加载文件。 composer update执行实现后,咱们仿照Laravel在我的项目下,建设 app 及 public 目录,用于贮存我的项目外围业务逻辑及提供对外拜访逻辑。 mkdir app && mkdir public2.增加路由组件执行完上述步骤后,咱们开始增加路由组件 illuminate/routing,然而该组件又依赖到了另一个组件 illuminate/events 组件,所以咱们须要将这两个组件一起引入进来。 执行 composer 操作如下: composer require "illuminate/events":"*"composer require "illuminate/routing":"*"引入实现后,咱们参照laravel建设路由定义文件 app/Http/routes/routers.php <?php$app['router']->get('/', function () { echo '欢送拜访 laramvc';});定义好路由后,持续参照laravel建设内部拜访路口文件 public/index.php ...

July 20, 2020 · 1 min · jiezi

laravel-中轻松容易的输出-SQL-语句

laravel-dump-sql laravel-dump-sql - laravel 中轻松容易的输入 SQL 语句装置$ composer require guanguans/laravel-dump-sql -v公布服务$ php artisan vendor:publish --provider="Guanguans\\LaravelDumpSql\\ServiceProvider"应用装置胜利后查问构建器会新增 toRawSql、dumpSql、ddSql 三个办法// 获取 SQLUser::where('id', 1)->toRawSql();DB::table('user')->where('id', 1)->toRawSql();// 打印 SQLUser::where('id', 1)->dumpSql();DB::table('user')->where('id', 1)->dumpSql();// 打印 SQL 并退出User::where('id', 1)->ddSql();DB::table('user')->where('id', 1)->ddSql();自定义办法名称公布配置文件$ php artisan vendor:publish --tag=laravel-dump-sqlconfig/dumpsql.php 文件中配置办法名称既可<?phpreturn [ /* * Get sql statement. */ 'to_raw_sql' => 'toRawSql', /* * Print SQL statements. */ 'dump_sql' => 'dumpSql', /* * Print SQL statements and exit. */ 'dd_sql' => 'ddSql',];

July 16, 2020 · 1 min · jiezi

gitlab安装自动部署laravel项目

gitlab安装使用docker安装gitlab1:docker pull gitlab/gitlab-ce2:docker run -d -p 4438:443 -p 8088:80 -p 2228:22 --name gitlab --restart always -v /home/gitlab/config:/etc/gitlab -v /home/gitlab/logs:/var/log/gitlab -v /home/gitlab/data:/var/opt/gitlab gitlab/gitlab-ce3:/var/opt/gitlab/gitlab-rails/etc/gitlab.yml 在容器里修改文件 host4:gitlab-ctl restart 重启在宿主机安装gitlab-runner 用docker安装踩了很多坑,因为内网物理服务器限制无法本地访问ssh免密登录// 切换到gitlab-runnersu gitlab-runner// 生成公私钥ssh-keygen//本地主机的公钥复制到远程主机的authorized_keys文件上,ssh-copy-id -i /home/gitlab-runner/.ssh/id_rsa.pub root@172.17.0.1 (172.17.0.1 宿主机ip,docker网络ip;ip addr)laravel项目自动构建yml文件 stages: - developdevelop: stage: develop cache: paths: - vendor/ tags: - develop script: - composer install - cp .env.example .env - php artisan key:generate - php artisan migrate - rsync -arvp -e "ssh" --rsync-path="sudo rsync" --delete-before . root@172.17.0.1:/xxx/xxxx/blog/ - ssh root@172.17.0.1 "cd /xxx/xxx/blog && php artisan config:cache && supervisorctl restart all" only: - developphp artisan config:cache // 这个命令要放到代码同步后,否则会缓存配置文件,导致路径不一致supervisorctl restart all 如果有队列任务是用supervis来管理,需要重启

July 7, 2020 · 1 min · jiezi

laravel-419-Page-Expired页面问题

在laravel项目中,表单正常操作时无异常,页面打开后长时间未操作,再次提交表单时,页面显示 “419 | Page Expired”错误。解决方式如下: <?phpnamespace App\Exceptions;use Exception;use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;use Illuminate\Session\TokenMismatchException;class Handler extends ExceptionHandler{ /** * A list of the exception types that are not reported. * * @var array */ protected $dontReport = [ // InvalidRequestException::class, ]; /** * A list of the inputs that are never flashed for validation exceptions. * * @var array */ protected $dontFlash = [ 'password', 'password_confirmation', ]; /** * Report or log an exception. * * @param \Exception $exception * @return void */ public function report(Exception $exception) { parent::report($exception); } /** * Render an exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @param \Exception $exception * @return \Illuminate\Http\Response */ public function render($request, Exception $exception) {// return parent::render($request, $exception); if (!$request->ajax() && ($exception instanceof TokenMismatchException)) { return redirect() ->back() ->withErrors('页面已过期 ,请刷新再试') // 错误提示信息 ->withInput($request->input()); // 可选 } return parent::render($request, $exception); }}

June 10, 2020 · 1 min · jiezi

Shadowfax-让Laravel佩上Swoole之剑

Swoole可以说是PHP的一把利剑,它拓展了PHP的边界,让众多PHPer们看到了高并发的曙光。利用Swoole来提高Laravel的性能,是一件非常值得投入的事情,这样既能获得Swoole的高性能,又兼顾了Laravel的高效率,两全其美。Shadowfax就是一款这样的拓展包,它简单易用,能够帮助开发者快速地将Laravel应用迁移到Swoole之上运行。 首先我们来看一下使用Shadowfax运行的Laravel应用的性能表现: 我使用wrk作为此次的benchmark工具,基于最新版的Laravel 7,但是移除了session相关的middleware。因为Laravel默认是启用了session的,而且session的驱动是file,如果在这种情况下去跑测试,每个请求都会创建一个session文件,这样跑出来的结果就没什么意义了。(追求性能的应用也不应该去使用file作为session驱动) 环境1: 硬件: 1 CPU, 4 Cores, 16GB MemoryMacOS 10.15.3PHP 7.3.12(启用opcache)Swoole 4.4.13Shadowfax 2(20个worker进程)这个环境也就是我个人的Macbook Pro,性能比较好。我用wrk启动4个线程,并发200进行压测: wrk -t4 -c200 http://127.0.0.1:1215/结果为 12430 rps: Running 10s test @ http://127.0.0.1:1215/ 4 threads and 200 connections Thread Stats Avg Stdev Max +/- Stdev Latency 26.44ms 31.44ms 212.73ms 84.28% Req/Sec 3.13k 839.99 6.07k 65.75% 124418 requests in 10.01s, 312.06MB read Socket errors: connect 0, read 54, write 0, timeout 0Requests/sec: 12430.20Transfer/sec: 31.18MB环境2: ...

June 7, 2020 · 1 min · jiezi

关于Laravel-与-Nginx-限流策略防止恶意请求

一、问题背景最近公司最近的几台线上服务器经常出现CPU覆盖过高,影响部分应用响应超时,产生了大量的短信和邮件报警,经过排查数据库日志和access.log,发现是API接口被刷,被恶意疯狂请求,最大一次大概120次/s。 之前没有过太多这方面经验,处理起来不是很顺畅,这次的问题刚好提了醒,经过这次的问题暴露,来记录一下解决方案和策略。 线上的部署方案是:nginx + laravel。 首先我们尝试从nginx层面入手,将占用更少的内存消耗,无需再转发到php-fpm上处理。 二、(恶意)请求特征想好很好的特征,就必须捕捉一定的特征,通过这个特征来有效的控制到恶意请求。 短时间内,IP对某接口产生大量请求user_agent,非正常信息或为空请求量比平时要高涨很多。三、限流策略(nginx)限制请求数首先的话.就是控制单IP时间上的请求次数和IP连接数,配置如下: http { limit_req_zone $binary_remote_addr zone=one:1m rate=1r/s; server { location /api/ { limit_req zone=one burst=5; } }}limit_req_zone主要控制单个IP的请求速率,使用漏桶算法来完成限制,limit_req_zone size,主要用于储存统计IP的请求信息,1M可以储存16000个IP,当每秒的请求超过了16000个的时候,其余访问都会被访问503 服务暂不可用。 上面的模板设置了,每秒最大不超过1个请求,最大延迟请求不超过5个。 如果我们的服务器每次接口的响应时间是在200ms-300ms,那我们对应的每秒的限制就应该设置成 1000ms / 接口响应耗时。 限制并发连接数限制完用户请求频率后,如果仍然还是存在很大的恶意请求,我们还可以进行并发数的限制。 http { limit_conn_zone $binary_remote_addr zone=one:1m; server { location /api/ { limit_conn one 10; } }}limit_conn_zone:主要是用于控制请求并发数,频率不能太快。 limit_conn_zone size跟limit_req_zone意思一致,可根据需要动态调控,上面的案例中,表示限制每个客户端IP最大并发连接数为10。 设定IP黑名单当某个IP请求过于频繁或者需要完全杜绝该IP的访问时,可以通过nginx的deny配置来禁止黑名单中的IP访问。 http { include blockip.conf; }黑名单配置 deny 195.91.112.66;deny 192.168.2.100;被添加黑名单后,再次访问就会出现403禁止访问. 限制UA(user-agent)信息http { server { if ($http_user_agent ~* "curl") { return 403; } }}上面就禁止了ua信息为curl的客户端,直接返回403。 ...

June 2, 2020 · 1 min · jiezi

Larvel-操作-MongoDB对内嵌数组增删改

PHP的MongoDB驱动中文文档:https://www.php.cn/manual/vie... PHP的MongoDB驱动官方文档:https://www.php.net/manual/zh... 有些细节都没写全,如想学习请阅读官方文档! 安装:https://blog.csdn.net/weixin_... 普通的增删改查与mysql驱动操作一样增$rs = DB::collection('集合名字')->insertGetId($param);$rs = DB::collection('集合名字')->insert($param);删$rs = DB::collection('集合名字')->where(["_id"=>1])->delete();改$rs = DB::collection('集合名字')->where(["_id"=>1])->update(['name'=<'遗失的美好']);查$result = DB::collection('集合名字')->where(["_id"=>1])->get();// 分页函数$results = DB::collection('集合名字')->paginate(10);// 这样也能做到分页 还有排序 orderBy() 排序函数,skip() 跳过几条 limit() 限制取出几条$rs = DB::collection('集合名字')->orderBy('age','asc')->skip(10))->limit(10)->get();对内嵌数组进行增删改,首先要知道MongoDB操作符:https://www.runoob.com/mongodb/mongodb-operators.html 增// 插入数组 $addToSet 插入时如果已经存在相同的则不插入 $rs = DB::collection('user_files_folder')->update(['$addToSet'=>['child'=>['name'=>'二傻子']])// 插入数组 $push 插入时如果已经存在相同的仍然插入$rs = DB::collection('user_files_folder')->update(['$push'=>['child'=>['name'=>'二傻子']])删$rs = DB::collection('user_files_folder')->update(['$pull'=>['child'=>['name'=>'二傻子']])改// 注意,这where条件如果需要多重结构则可以用.连接$set是修改操作符,对应修改对象(数组)修改对象如果需要多重结构也可以用.连接,这里的$符号代表对应的键(因为这里的数据结构是一个数组,$代表对应的序号,也可以写死成 0-9之类的数字)DB::collection('stock')->where(['info.id'=>"118b110212"])->update([ $set'=>[ 'info.$.id'=>"118b110jkjkjk" ]]);

May 26, 2020 · 1 min · jiezi

lumen-request-获取-header-头参数-token

lumen request 获取 header 头参数 token $token = $request->bearerToken();以下是校验 token 合法性的一个方法,可以用在中间件中使用: /** * 验证 token 合法性 * @param Request $request * @param $err * @return bool * @throws \Exception */ public static function checkToken(Request $request, &$err) { $token = $request->bearerToken(); if (!$token) { $err = 'token not found'; return false; } $user = []; //检查redis里边是否存在用户token if (Redis::exists(Constant::REDIS_TOKEN_PREFIX . $token)) { $userJson = Redis::get(Constant::REDIS_TOKEN_PREFIX . $token); if (!$userJson) { $err = 'data error'; return false; } $user = JsonHelper::decode($userJson); } else { //不存在,就请求GRpc获取 $client = new GRpcClient(); $params['session_id'] = $token; $ret = $client->setCmd(GRpcCmd::CHECK_LOGIN)->send($params); if (!is_array($ret)) { $err = 'token error:' . $client->getMsg(); return false; } //获取到之后就存到redis $user['id'] = $ret['user_id'];//用户ID $user['phone'] = $ret['phone'];//手机号 $user['channel'] = $ret['register_channel'];//注册渠道 $user['gold'] = $ret['gold'];//金币 Redis::setex(Constant::REDIS_TOKEN_PREFIX . $token, 7200, JsonHelper::encode($user)); } return true; }

May 26, 2020 · 1 min · jiezi

Laravel-REST-API-响应生成器

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...用于Laravel的REST API 响应生成器是 Marcin Orlowski的一个软件包,用来构建JSON API响应。根据作者的说法,该软件包可帮助您进行数据转换和本地化等工作: ResponseBuilder 是由 REST API 开发人员为那些 REST API 开发者而编写的扩展包,它基于我对各种 REST API 开发「双方」(API 开发人员和 API 消费者)的长期经验。它的特点在于:轻量级,具有简单易用的公共方法,涵盖多个潜在的用例,即时的数据转换,本地化的支持,自动错误信息的构建,对链式 API 的支持,以及(我希望如此) 详尽的文档。这个包提供的最简单的例子是从控制器中返回以下内容: return ResponseBuilder::success();生成的客户端JSON如下所示: { “success”: true, “code”: 0, “locale”: “en”, “message”: “OK”, “data”: null}如果你想要为API中的常见错误构建消息代码,则可以执行以下操作: return ResponseBuilder::error(MyErrorCodes::SOME_CODE);如果你传递了 205错误码,则会显示以下信息: { “success”: false, “code”: 205, “locale”: “en”, “message”: “Your error message for code 250”, “data”: null}查阅详情 文件 有关这个包的更多案例,你可以了解这个包的更多信息,获取完整的安装说明,并在 GitHub 上查看源代码 MarcinOrlowski/laravel-api-response-builder.

November 5, 2019 · 1 min · jiezi

方便的-Bash-终端技巧大集合

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...Bash 集合我很高兴你在这里!几年前我从事生物信息学方面的研究工作。对那些简单的 bash 命令感到惊讶,他们比我的枯燥脚本快很多。通过学习命令行的快捷方式和脚本帮助我节省了很多时间。近年来,我从事云计算相关的工作,并在这里继续记录那些有用的命令。并且我在努力的使他们简短而且迅速。我主要使用 Ubuntu,RedHat ,Linux Mint 以及 CentOS 系统,如果命令在您的系统上不生效,那么我很抱歉。 该博客将重点介绍我从工作以及 LPIC 的考试中获得的用于解析数据和 Linux 系统维护的简单命令,但是他们可能来自于亲爱的 Google 和 Stackoverflow。 英语和 bash 并不是我的母语,请随时纠正我,谢谢。如果你知道其他有趣的命令,请教教我。 这是更新潮的版本Bash-Oneliner~ [](https://github.com/onceupon/B... bash 一行命令终端技巧变量Grep命令Sed命令Awk命令Xargs命令Find命令条件和循环数学时间下载随机Xwindow工具系统硬件联网其他[](https://github.com/onceupon/B...使用 Ctrl 键Ctrl + n : 类似向下的键Ctrl + p : 类似向上的键Ctrl + r : 反向搜索命令的历史记录(按住 Ctrl + r )Ctrl + s : 终端停止输出.(译者注:如 apt / yum,nload,watch 等,按 Enter 继续输出)Ctrl + q : 在 Ctrl + s 之后重新恢复之前的 terminal.Ctrl + a : 移动光标到行的开始处Ctrl + e : 移动光标到行的结尾处Ctrl + d : 如果当前的 terminal 命令行有输入,Ctrl + d 或删除光标处的字符,否则会退出当前的 terminalCtrl + k : 删除从当前光标到结尾的所有字符Ctrl + x + backspace : 删除当前光标到行开始的所有字符Ctrl + t : 交换当前光标下的字符和其前面字符的位置。Esc + t 交换光标前面的两个单词Ctrl + w : 剪切光标之前的单词,然后 Ctrl + y 粘贴它Ctrl + u : 剪切光标之前的行; 然后 Ctrl + y 粘贴它Ctrl + _ : 撤销之前的操作Ctrl + l : 相当于清除Ctrl + x + Ctrl + e : 召唤起 $EDITOR 环境变量设置的编辑器程序,对多行命令有效[](https://github.com/onceupon/B...Esc + u# 将文本从光标的开始到结尾的单词转换为大写Esc + l# 将文本从光标的开始到结尾的单词转换为小写Esc + c# 将光标下的字母转换为大写[](https://github.com/onceupon/B... (例如 e.g. 53)!53[](https://github.com/onceupon/B...!![](https://github.com/onceupon/B... : echo 'aaa' -> 现在运行: echo 'bbb')#最后的一条命令: echo 'aaa'^aaa^bbb#echo 'bbb'#bbb#注意只有唯一的第一个 aaa 将会被替代,如果你想替代所有的 aaa,使用「:&」替代:^aaa^bbb^:&#或者!!:gs/aaa/bbb/[](https://github.com/onceupon/B... (e.g. cat 文件名)!cat# 或者!c#再次运行cat文件名[](https://github.com/onceupon/B... 通配符# '*' 用作文件名扩展的 "通配符" 。/b?n/?at #/bin/cat# '?' 用作文件名扩展的单字符 "通配符" 。/etc/pa*wd #/etc/passwd# ‘[]’ 用于匹配范围内的字符。ls -l [a-z]* #列出所有文件名中带有字母的文件。# ‘{}’ 可用于匹配多个模式的文件名 ls {*.sh,*.py} #列出所有.sh和.py文件[](https://github.com/onceupon/B...$0 :shell或shell脚本的名称。$1, $2, $3, ... :位置参数。$# :位置参数的数量。$? :最新的管道退出状态。$- :为shell设置的当前选项。$$ :当前shell(不是subshell)的pid。$! :最新后台命令的PID。$DESKTOP_SESSION 当前显示管理器$EDITOR 首选文本编辑器。$LANG 当前语言。$PATH 搜索可执行文件的目录列表(即准备运行的程序)$PWD 当前目录$SHELL 当前 shell$USER 当前用户名$HOSTNAME 当前主机名筛选[返回顶部] ...

November 4, 2019 · 19 min · jiezi

php项目目录的合理划分和Pipeline-组件的使用场景

php项目目录的合理划分和Pipeline 组件的使用场景这是一篇迟到的文章,很早之前就一直想写了,可是经验不足有些地方理解的不透侧,当然,现在这篇文章可能也是浅尝辄止,希望不要喷我开篇首先,可以先导读一下如下这篇文章,有助于提升一下代码质量 Laravel 的十八个最佳实践 单一职责原则 通俗点介绍则是,一个功能为一个功能所做事情。例如,我们需要获取用户信息,那简而言之,编写的 getUserInfo 则只用它来做一件东西。当然,这只是一个方法,如果一个类呢,我们需要怎么来定义 如今大家遵循的大多数是 mvc 规范,现在的开发流程下,大概v,也就是视图层早已经消失殆尽 mc的关系如何处理呢,我建议大概是如下几种 -app--Model // 模型层--Controller // 控制器层--Traits --Stores // 处理类--Tools // 工具类--Routers // 扩展路由模型和控制器就不需要多说了 Traits这个名词的解释,Trait 就不多书了,可见官方手册 : https://www.php.net/manual/zh... 这里主要存放一些复用的公共函数方法,例如获取器,验证器等等, Stores用来存放模型或者控制器不方便写的一些代码,例如返回一个商品信息,需要针对商品清单从其他数据库或则数据表进行补全完整的信息例如,购买人次,成交额等等,这个时候,这些东西既不适合交给控制器也不适合交给模型层 Tools工具类,这里存放一些工具方法,例如处理某个数据集的公用或者某个组件功能需要使用的方法常见的有响应方法,打日志的方法等等 Routers路由扩展文件,这个文件的意义就在于,当系统或者功能庞大起来之后,路由将会变得非常不好管理,基本上在后台管理中,一个功能可能就产生5个左右路由 这个时候就需要其将路由文件拆分开来 以上的操作,当然不能一概而论,应当适当的针对业务场景进行处理,例如简单的一个后台,管理用户的功能就无需如此繁杂。当功能越来越多而不好管理的时候才能适当的发挥它的最大作用 重要篇Pipeline 组件 是什么 参考文章:【单篇】Laravel Pipeline 组件的实现原理 这是一个非常有趣的功能,大家应该或多或少的使用过中间件,是不是从来没有过去了解中间件呢 其实,中间件背后的逻辑及其实现也就是 Pipeline 的简化版 中文寓意是通道的意思 使用场景上代码: 如上,我们发现,第一张图我们代码非常非常少,最后一张图,返回的数据字段非常非常多,而查询语句也并没有查询多少东西 使用场景大概如下 有一批商品信息,我们只知道他的商户id和商品id (product表)由此,我们需要给前端返回 (订单成交额 order表)(分类信息 tag表)(成交用户属性信息 user表)(优惠信息 coupone表) 这个时候,按照以往的逻辑,我们有几种解决方案 foreachforeach + 类处理大概第二种方法用的人会最多,循环商品信息,当if需要成交额当时候就去成交额的表中查询,然后给补齐上 第一种方法就忽略吧,都是写在一个方法里面来foreach, 极度不推荐 这个时候就 Pipeline 它上场了,通过传导数据给它,在 Pipeline 的dispatcher中添加类例如补齐订单成交额,则可以添加 Order::Class 等等 ...

November 2, 2019 · 1 min · jiezi

将数据从-Laravel-传送到-vue-的四种方式

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...在过去的两三年里,我一直在研究同时使用 Vue 和 Laravel 的项目,在每个项目开发的开始阶段,我必须问自己 “我将如何将数据从 Laravel 传递到 Vue ?”。这适用于 Vue 前端组件与Blade模板紧密耦合的两个应用程序,以及运行完全独立于 Laravel 后端的单页应用程序。 这里有四种不同的方法从一个到另一个获取数据。 直接回显到数据对象或组件属性中 赞成: 简单明了反对: 必须与嵌入到Blade模板中的Vue应用程序一起使用可以说是将数据从 Laravel 应用程序移动到 Vue 前端的最简单方法。使用上面的任何一种方法,您都可以将 JSON 编码的数据回送给您的应用程序或其组件。 然而,最大的缺点是可扩展性。您的 JavaScript 需要直接暴露在模板文件中,以便引擎可以呈现您的数据。如果您使用 Vue 向 Laravel 站点的页面或区域添加一些基本的交互,这应该不是问题,但是您很容易就会遇到将数据强制放入压缩脚本的困难。 对于 Laravel 5.5+ 使用 json 指令: 使用自定义组件和 Laravel 自身的 json blade指令可以让您轻松地将数据移动到道具中。此方法允许您划分 Vue 代码,将脚本与 Webpack 或 Mix 捆绑在一起,同时仍可以直接向其中注入数据。 将属性作为全局窗口注入 赞成: 在整个Vue应用程序和任何其他脚本中全局可用反对: 可能很混乱,通常不建议用于大型数据集虽然这看起来有点老生常谈,但将数据添加到窗口对象中可以轻松地创建全局变量,这些变量可以从应用程序中使用的任何其他脚本或组件访问。在过去,我用它作为存储和访问 API 基 URL、公钥、特定模型 ID 和各种其他需要在整个前端使用的小数据项的方法。 不过,使用此方法有一点需要注意,这就是访问 Vue 组件内部数据的方式。在模板内部,您将无法使用以下内容,因为 Vue 假定您尝试访问的窗口对象位于同一组件内: // 不会起作用<template> <div v-if="window.showSecretWindow"> <h1>这是个秘密窗口,别告诉任何人!</h1> </div></template>相反,您需要使用返回值的计算方法: ...

October 17, 2019 · 2 min · jiezi

Laravel-Authorization支持-ACLRBACABAC-等模型的授权库

Laravel Authorization 基于 Casbin ,是一个支持访问多种访问控制模型(如ACL,RBAC,ABAC等)的授权库。在这之前,你需要先了解 Casbin 。 安装使用 Composer 安装: composer require casbin/laravel-authzLauthz\LauthzServiceProvider 是 auto-discovered 的,并且默认情况下已注册,但是如果您想自己注册,可以在 config/app.php 中添加 ServiceProvider: 'providers' => [ /* * Package Service Providers... */ Lauthz\LauthzServiceProvider::class,]Enforcer facade 也是 auto-discovered,但是如果您想手动添加它,在 config/app.php添加: 'aliases' => [ // ... 'Enforcer' => Lauthz\Facades\Enforcer::class,]要发布配置,请运行 vendor:publish 命令: php artisan vendor:publish这就自动创建 Model 配置文件 config/lauthz-rbac-model.conf 和 一个新的 Lauthz 配置文件 config/lauthz.php。 要迁移迁移,请运行migrate命令: php artisan migrate这将创建一个 rules 数据表。 用法快速开始安装后,您可以执行以下操作: use Enforcer;// adds permissions to a userEnforcer::addPermissionForUser('eve', 'articles', 'read');// adds a role for a user.Enforcer::addRoleForUser('eve', 'writer');// adds permissions to a ruleEnforcer::addPolicy('writer', 'articles','edit');您可以校验用户的权限,如下: ...

October 14, 2019 · 2 min · jiezi

你是如何处理-PHP-代码中的枚举类型-Enum-的

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...本文旨在提供一些更好的理解什么是枚举,什么时候使用它们以及如何在php中使用它们. 我们在某些时候使用了常量来定义代码中的一些常数值.他们被用来避免魔法值.用一个象征性的名字代替一些魔法值,我们可以给它一些意义.然后我们在代码中引用这个符号名称.因为我们定义了一次并使用了很多次,所以搜索它并稍后重命名或更改一个值会更容易. 这就是为什么看到类似于下面的代码并不罕见. <?phpclass User { const GENDER_MALE = 0; const GENDER_FEMALE = 1; const STATUS_INACTIVE = 0; const STATUS_ACTIVE = 1;}以上常量表示了两组属性,GEDNER_* 和 STATUS_*。他们表示一组性别和一组用户状态。每一组都是一个枚举 。枚举是一组元素(也叫做成员)的集合,每一个枚举都定义了一种新类型。这个类型,和它的值一样,可以包含任意属于该枚举的元素。 在上面的例子中,枚举借助于常量,每一个常量的值都是一个成员。注意,这样做的话,我们只能在常量包含的类型中取值。因此,我们在写这些值的时候不会有类型提示,不知道详细的枚举类型。 来看一个简短的例子, 但我们假定例子中有更多的代码 <?phpinterface UserFactory { public function create( string $email, int $gender, int $status ): User;}$factory->create( $email, User::STATUS_ACTIVE, User::GENDER_FEMALE);第一眼看上去代码很好,但是他只是碰巧正确运行了!因为两个不同的枚举成员实际上是同一个值,调用create方法成功,是因为这最后两个参数被互换了不影响结果。尽管我们检查方法接受的值是否有效,运行界面也不会警告我们,测试也会通过。有人能正确的发现这些bug,但是它也很可能被忽视掉。之后一些情况,比如合并冲突的时候,如果它的值改变了,它可能会引起系统异常。 如果使用标量类型,我们会受限于这种类型,无法辨别这两个值是是不是属于两个不同的枚举。 另一个问题是这个代码描述的的不是很好。想象一下 create 方法没有引用常量。$gender 被别人看作为一个枚举元素将是有多么困难?看这些元素在哪里被定义又有多么困难?我们之后将会阅读那些代码,因此我们应该尽可能是让代码易于阅读以及和通过。 我们可以做得更好吗? Sure! 这个方法就是是使用类实例作为枚举元素,类本身定义了一个新的类型。 直到PHP 7,我们可以安装 SPL类 PECL扩展并且使用SplEnum 。 <?phpclass YesNo extends \SplEnum{ const __default = self::YES; const NO = 0; const YES = 1;}$no = new YesNo(YesNo::NO);var_dump($no == YesNo::NO); //truevar_dump(new YesNo(YesNo::NO) == YesNo::NO); //true我们扩展 SplEnum 并且定义用于创建枚举元素的常量。枚举元素是我们手动构造的对象,在这种情况下是常量值本身。 我们可以将整型与对象进行比较,这可能很奇怪。 另外,正如文档所述,这是一个仿真的枚举。 PHP本身并不支持枚举类型,所以我们在这里探讨的所有内容都是仿真的。 ...

October 9, 2019 · 2 min · jiezi

Laravel54广播事件pusher-的配置以及使用

发表于2年前, 整理文章迁移过来, 原文地址https://learnku.com/articles/...最近要写一个聊天室,于是了解了一下laravel的事件广播,参考资料来源于http://laravelacademy.org/pos... 但是在跟随博主动手的时候, 发现事件成功触发, 但是pusher调试控制台上并没有收到事件。经过调试找到问题所在。首先我们先创建一个事件: php artisan make:event TestEvent最终, 事件的代码如下, 这里有一个注意点就是 如果该事件没有继承use IlluminateContractsBroadcastingShouldBroadcast; 接口,那么触发事件,将不会发送事件至pusher 服务器上.use ...// 如果该事件没有继承use Illuminate\Contracts\Broadcasting\ShouldBroadcast; 接口,那么触发事件,将不会发送事件至pusher 服务器上.class TestEvent implements ShouldBroadcast{ use Dispatchable, InteractsWithSockets, SerializesModels; // 类型需为public public $msg; public function __construct($msg) { $this->msg = $msg; } public function broadcastOn() { return [ 'test' ]; }}为了测试方便,我们创建一个artisan 命令来触发事件. php artisan make:command TestEventCommand打开命令类 app/Console/Commands/TestEventCommand.php 编辑后如下 class TestEventCommand extends Command{ protected $signature = 'pusher:test {message}'; protected $description = 'pusher test'; public function __construct() { parent::__construct(); } public function handle() { event(new \App\Events\TestEvent($this->argument('message'))); }}打开 app/Console/Kernel.php, 将刚创建的命令类添加至 $commands ...

October 8, 2019 · 1 min · jiezi

解读-Laravel-中的扩展自动注册机制Package-Autodiscovery

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...在进入探究 Laravel 包提供者与门面如何自动发现之前,让我们先粗浅剖析一下PHP 中包的概念。 一个包就是一个在多个项目内可复用的代码片段,例如 包 spatie/laravel-analytics 可以让你在laravel项目内,用一种简易方式从谷歌统计(Google Analytics)中取回数据,该包被托管 在 GitHub 上,由 Spatie进行维护,它们会持续发布,更新和修复该包 bug,如果你在项目当中使用该包,希望获取这些一旦发布的更新和修复,无须担心使用Composer 从 Github 上 拷贝一份新代码即可。 Composer 是一个 PHP 依赖管理工具。它允许你声明项目库依赖且管理(安装/更新)它们。 -- 详见官网 getcomposer.orgLaravel 自带 composer.json文件,文件内的 require 或 require-dev条目下,给出了你扩展应用功能需用到的包,执行 composer update: { "require": { "spatie/laravel-analytics": "3.*", },}你也可以使用下面命令,达到同样的效果 composer require spatie/laravel-analyticsComposer所做的工作在于,拉取你所需版本包,下载到  vendor 目录,上述命令执行完毕, 包内所有类和文件被加载进项目,你就可以马上使用它们了,每次当你再次执行 composer update ,Composer 将会重新获取(译者注 通常从 composer 仓库拉取)更新该包,并且自动更新位于你项目  vendor 目录下的文件。 在 Laravel 项目中使用某些 Laravel包 需要以下额外几个步骤 注册服务提供者注册别名/门面发布资源如果你看过 Spatie包安装说明 你会发现,在继续下一步这前,项目配置必须注册服务提供者和一个门面,是一个很好的习惯,这个步骤由 Taylor Otwell定义,只是一个非必要条件, Dries Vints,且达到无论何时你决定引入一个新包或移除包,服务提供者和门面皆可被自动发现。 重温 Taylor 的新特性声明  在媒体上. 什么是服务提供者和门面?服务提供者负责将事物绑定到 Laravel 的服务容器中,并通知 Laravel 在哪里加载包资源,例如视图,配置和本地化文件。-- laravel.com 文档你可以在上面阅读有关服务提供者的更多信息 官方文档. ...

October 8, 2019 · 2 min · jiezi

我是如何使用laravel写爬虫应用的

上面这个图是我设计的爬虫架构,这个架构逻辑比较简单。 首先是链接池,链接池存储需要爬取的网页链接,每个链接有当前爬取状态,尝试次数等信息,爬取状态分为:waiting(等待),going(正在进行),success(爬取成功),fail(爬取失败)。链接的默认状态是waiting,当爬虫正在爬取这个链接的内容的时候,链接进入going状态,链接内容爬取成功进入success状态,爬取失败进入fail状态。链接的另一个参数是尝试次数,当链接爬取失败则尝试次数加1并再次进入waiting状态,设定尝试次数阈值,比如设定阈值为3,当尝试次数超过3次,则进入fail状态。 爬虫管理者负责创建爬虫任务,我们可以创建一个task来定期运行爬虫管理者。爬虫管理者从爬虫池中选取一定数量的处于waiting状态的链接,创建爬虫任务。 爬虫任务接受一个目标链接,然后针对链接的格式运行对应的解析器。如果发现新的目标链接,则将新发现的链接放入链接池。这个地方需要注意的是爬虫在请求链接内容的时候,要使用代理,这样可以防止同一个ip频繁请求被封的情况。 刚开始链接池是空的,所以我们需要放入第一个目标链接,这样爬虫会不断的发现新链接,然后将新链接作为目标链接再次爬取内容,如果效果好的话,爬虫会一直运行知道没有新的链接发现未知。 下面这个是我最近做的一个微信小程序,用来快速查找澳洲保健品中文信息的小工具。

October 4, 2019 · 1 min · jiezi

扩展推荐-Laravel-Tenancy-多站点架构方案

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...Laravel Tenancy 是由 Daniël Klabbers、Paulo Trajano 和 Bertrand Kintanar 发布的扩展包,使你的 Laravel 应用支持多租户。 这个不引人注意的扩展包,使你的应用支持多租户,来服务于多个站点,即一套代码库配置一个或者多个主机名。清晰的分离了资源、数据库和覆盖每个租户的逻辑的能力。适合那些为不同用户重用功能的营销公司和新兴公司,构建软件作为服务。 Laravel Tenancy 扩展包包含以下特点: 用 Laravel 框架集成;事件驱动的可扩展架构;关闭设置项集成到 Web 服务器中;能添加特定租户的配置、代码和路由等。对在多租户应用中,数据库架构的标准处理包括: 为系统数据和租户表预设一个数据库。为系统数据的一个数据库和一些特殊租户数据库。Laravel Tenancy 扩展包支持两种方法,你可以通过事件监听方式进行手工配置。  tenancy/tenancy 包继承于 hyn/multi-tenant ,这就意味着在生产环境中使用 hyn/multi-tenant 包来替代  tenancy/tenancy ,仍然可以正常工作。 详细请参照 hyn/multi-tenant 文档 ,了解如何安装和具体实现。

October 3, 2019 · 1 min · jiezi

Laravel-服务容器必知必会

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...学习如何用 Laravel 构建一个应用程序,不仅仅是学习使用不同的类和框架中的组件,也不是要记住全部的 artisan 命令或所有的辅助函数(我们有 Google)。学习用 Laravel 编码是学习它的哲学和优雅迷人的语法。 我个人觉得是一件艺术和工艺品(巧合的是 Laravel 工程师有时也被称作 Web 艺术家)。对其他框架这也是真理。 服务容器和 IOC 容器是 Laravel 哲学的主要部分。作为一个 Laravel 开发者,理解并能正确的使用服务容器是你掌握它的重要部分, 因为它是任何 Laravel 应用的核心。 基础虽然 IOC 容器本质上只是一个普通的 PHP 类, 但是我喜欢将它看做"袋中的技巧"。 这个"袋子"就是我们放置或者"绑定"任何我们需要运行在 Laravel 应用中的对象服务, 从接口实现到目录路径以及其他等等。因此叫做"袋中的技巧" 现在我们拥有了一个包含所有绑定对象服务的单一对象( IOC 容器), 因此在我们的代码中,任何时候都可以很容易的从这个单一对象中获取或者"解析"这些对象服务 绑定的处理方式现在假设我们有一个特别功能的 FooService 类。 <?phpnamespace App\Services;class FooService{ public function __construct() { ... } public function doSomething() { // Code for Something. }}如果我们要调用类的 doSomething 方法,我们可能会这样做 : $fooService = new \App\Services\FooService();\$fooService->doSomething();这看起来没有什么问题,但比较麻烦的是这儿的 'new' 关键字,我的意思是虽然这样也很好,但是我们可以做的更优雅 (记住写代码要像 Laravel 一样,用优雅的方式)。 ...

October 2, 2019 · 2 min · jiezi

API-接口设计-GraphQL-和-REST-怎么选择

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...这个话题在开发社区里已经讨论过一段时间,人们对此有不同的看法与观点,那么我应该使用哪一个? 有很多东西需要成长但富有活力的新成员还是经验丰富的老成员? 在此之前让我们了解下 REST 和 GraphQL吧。 REST 是什么?REST即表述性状态传递(英文:Representational State Transfer,简称REST),它符合特定的指南,是 Web API 实现的约束。是 Roy Fielding 博士在他的博士论文中提出来的一种软件架构风格。它鼓励客户端和服务器以无状态模式交换信息。 请记住,并非所有 API 都是 REST,但所有 RESTful 服务都是 API。 GraphQL 是什么?GraphQL是Web API 的查询语言。它由Facebook于2012年创建,并于2015年开源。它既不是架构模式,也不是Web服务。它是个中介,用来查询从各种数据源接收的数据。 这些数据源可以是数据库或Web服务。 多年来,REST已成为Web API的事实上的标准。 由于它使用了标准的HTTP方法(GET,POST,PUT,DELETE等),随着互联网上的Web应用程序的增加,它也得以发展和普及。 此外,它的语言和平台无关,使其成为创建Web服务的更好选择。 因为每个数据都被视为在调用URL时要发送的资源,所以甚至可以使用Web浏览器或使用cURL请求来调用它。 REST的缺点虽然REST非常成功,但由于RESTful服务的规模和复杂性不断增长,因此它的缺点变得非常明显 1. 多端 (多次数据交互)在 RESTful 服务中一个 URL 表示一个资源。因此,当要获取多个资源时你必须请求多个不同的 URL,进而带来多次数据交互。 当我们考虑一个博客应用。一篇博客下面有多条评论的情形。通常我们要调用的 URL 如下 GET /posts/<postId> - 获取特定的博客文章GET /posts/<postId>/comments - 获取上面博客文章关联的所有评论GET /posts/<postId>/comments/<commentId> - 获取特定博客下的特定评论你会发现我们要请求的 URL 多了不少。这是因为实体 (这里可以理解为博文和评论)之间的关联关系更加复杂了。随着应用变得越来越复杂,管理这些 API 也变得更加困难。 2. 过度获取/获取后 数据有时候,当您请求 API 接口时,您会获得不必要的数据和相关数据,有时候您无法获得足够的数据,所以您最终会进行多次往返。 这是 RESTful 服务中的常见问题。 在某些情况下,您可能只需要 2 - 3 个值,但您可以获得大约 20 - 25 个值作为响应。 这只会通过增加响应时间,导致传输大量未使用的数据。 在后一种情况下,您获取的信息可能需要比从单个 URL 获取的信息要多,因此有必要进行多次往返。 这也导致客户端获取所有所需数据所花费的时间成本增加。 ...

October 1, 2019 · 2 min · jiezi

教程-Laravel-中使用-JWT-认证的-Restful-API

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...在此文章中,我们将学习如何使用 JWT 身份验证在 Laravel 中构建 restful API 。 JWT 代表 JSON Web Tokens 。 我们还将使用 API 为用户产品创建功能齐全的 CRUD 应用。 在使用跨平台应用程序时, API 是一个非常不错的选择。 除了网站,您的产品可能还有 Android 和 iOS 应用程序。 在这种情况下, API 也是同样出色的,因为您可以在不更改任何后端代码的情况下编写不同的前端。 使用 API 时,只需使用一些参数点击 GET , POST 或其他类型的请求,服务器就会返回 JSON(JavaScript Object Notation) 格式的一些数据,这些数据由客户端应用程序处理。 说明我们先写下我们的应用程序详细信息和功能。 我们将使用 JWT 身份验证在 laravel 中使用 restful API 构建基本用户产品列表。 A User 将会使用以下功能 注册并创建一个新帐户登录到他们的帐户注销和丢弃 token 并离开应用程序获取登录用户的详细信息检索可供用户使用的产品列表按ID查找特定产品将新产品添加到用户产品列表中编辑现有产品详细信息从用户列表中删除现有产品A User 必填 nameemailpasswordA Product 必填 namepricequantity创建新的项目通过运行下面的命令,我们就可以开始并创建新的 Laravel 项目。 composer create-project --prefer-dist laravel/laravel jwt这会在名为 jwt 的目录下创建一个新的 Laravel 项目。 ...

September 19, 2019 · 5 min · jiezi

Laravel58-入门系列一开启第一个Hello-World程序

一、环境要求Laravel 5.8对于PHP环境要求如下: PHP >= 7.1.3OpenSSL PHP 扩展PDO PHP 扩展Mbstring PHP 扩展Tokenizer PHP 扩展XML PHP 扩展Ctype PHP 扩展JSON PHP 扩展二、工具PHP环境,使用xampp集成环境,注意下载PHP7.1.3以上版本代码ide,sublime text 3版本控制工具git三、安装LaravelLaravel 使用 Composer 管理依赖,所以,安装之前确保已经在机器上安装了 Composer(如果尚未安装的话参考这份文档去安装吧)。 Composer Project 安装composer create-project --prefer-dist laravel/laravel blog5.8 5.8Laravel 安装器安装可以先使用composer 命令安装Laravel命令 composer global require laravel/installer再执行install操作 laravel new blog5.8上述两种安装方法都会在当前目录下生成一个blog5.8的文件夹,并执行安装操作。但是,请注意,使用laravel安装器安装,现在是不能指定版本的,所以总是安装最新的laravel版本。网上一些文章已经过时,现在最新的 laravel new 命令是不支持指定版本的。 如果上述安装操作成功了,则可以直接配置xampp的vhost,指定根目录为blog5.8/public目录,然后就可以访问了。 或者,你也可以进入blog5.8文件夹,执行php artisan serve命令,启动自带的service查看效果。默认,访问地址为 http://localhost:8000 四、目录结构Laravel 的目录以及每个目录的说明如下: |--- |--app 主要业务文件目录 |--Console 命令行目录 |--Exceptions 异常渲染目录 |--Http 请求处理目录 |--Controllers 控制器目录 |--Middleware 中间件目录 |--Providers 服务提供者目录 |--bootstrap 启动加载文件目录 |--configs 配置文件目录 |--database 数据库文件目录 |--factories 数据填充factory文件目录 |--migrations 数据迁移文件目录 |--seeds 假数据生成文件目录 |--public 请求根目录 |--resources 资源目录 |--views 视图模板目录 |--route 路由文件目录 |--storage 文件存储目录五、创建第一个应用Hello World!进入到blog5.8/routes目录下,打开web.php文件,添加一个hello的路由,并输出Hello World!。修改之后的内容如下: ...

September 11, 2019 · 1 min · jiezi

PHP-高性能-Excel-扩展-127-发布

为什么使用 php-ext-excel-exportxlswriter是一个PHP C扩展,可用于在Excel 2007+ XLSX文件中写入多个工作表的文本,数字,公式和超链接。 它支持以下功能:100%兼容的Excel XLSX文件完整的Excel格式合并单元格自动筛选图表数据验证和下拉列表工作表PNG / JPEG图像用于写入大文件的内存优化模式适用于Linux,FreeBSD,OpenBSD,OS X,Windows编译为32位和64位FreeBSD许可证唯一的依赖是zlib 基准测试测试环境: Macbook Pro 13 inchIntel Core i516GB 2133MHz LPDDR3 Memory128GB SSD Storage.导出两种内存模式,导出100W行数据,单行27列,每个单元格19个中文字符常规模式: 耗时 29S,内存占用 2083MB;固定内存模式: 耗时 52S, 内存占用 <1MB;读取读取 100W 行数据,每行1列,单元格数据为int全量读取: 耗时 3S, 内存占用 558MB;游标读取: 耗时 2.8S, 内存占用 <1MB;仓库地址Github:https://github.com/viest/php-ext-excel-export Gitee:https://gitee.com/viest/php-ext-xlswriter PECL:https://pecl.php.net/package/xlswriter 文档https://xlswriter-docs.viest.me End最后的最后请不要忘记star

September 10, 2019 · 1 min · jiezi

如何在-Laravel-中正确地返回-HTTP-状态码

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...在 API 中返回状态码是很重要的,因为响应处理程序是工作在 API 的响应状态码之上的。 写 API 时其中有一个重要的地方是更好的处理响应状态码。以前,我一般会使用不常用的 Integer 类型数字作为 HTTP 状态码 。看下面的这个例子: <?php namespace App\Http\Controllers;use App\Http\Controllers\Controller;use App\Post;Class PostsController extends Controller{ public function store(){ $post = new Post(request()->only('title', 'description')); request()->user()->posts()->save($post); return response()->json(['post' => $post], 201); }}在 API 的调用期间 ,如果数据已被创建,那么将会响应 HTTP 201 状态码,但是很多的开发者并不知道 201 状态码,他们更熟悉 200 成功状态码 。使用 Symfony Response 类可以解决这个问题 。它包含了所有的 HTTP 状态码,并且使用更简单易懂的命名 。以上的代码可以修改为如下代码: <?php namespace App\Http\Controllers;use App\Http\Controllers\Controller;use App\Post;use Symfony\Component\HttpFoundation\Response;Class PostsController extends Controller{ public function store(){ $post = new Post(request()->only('title', 'description')); request()->user()->posts()->save($post); return response()->json(['post' => $post], Response::HTTP_CREATED); }}这个类包含了所有定义的 HTTP 状态码,先来看看其中的一些状态码: ...

September 10, 2019 · 1 min · jiezi

PHP框架のLaravel

1.特点* 1).优点 A).优雅,框架结构组织清晰(抽象了中间件,任务,服务等模块) B).提供的artisan开发工具开发效率高 C).社区活跃完善,辅助工具丰富 D).提供了简化的轻量级框架LUMEN2).缺点 A).有些过于优雅丧失了一些性能(框架重) B).文档简单,学习成本2.基础* 1).Repository 与 Model A).Repository:数据仓库【直接DB | 封装model(封装数据查询和存储逻辑 | 更换、升级ORM 引擎,不影响业务逻辑)】 B).Model :数据库操作【直接DBEloquent ORM】2).Request 与 Response A).Request :请求【注入使用 | 门面使用】 a).注入使用 $request->paramName b).门面使用 Request::input('paramName') B).Response:响应 a).视图,Json,文件,重定向3).中间件(Middleware) 自定义中间件之后要在Kernel注册 A).全局中间件:通用校验 B).中间件组 :对于分组使用 【提供Provides注册config/app】 C).路由中间件:特殊校验(权限)3.概念* 1).门面:2).契约:3).容器:4).管道:

September 9, 2019 · 1 min · jiezi

使用-Laravel-Envoy-实现自动部署

导语以前是使用 Git Hook 实现自动部署,现在改为使用 Laravel Envoy,记录一下。 安装以及初始化前提条件是可以免密登陆服务器,可以看这篇文章 执行 composer global require laravel/envoy 进行安装新建文件 envoy init user_name@ip_path,执行操作后,会创建 Envoy.blade.php 文件如下@servers(['web' => 'user_name@ip_path'])@task('deploy') cd /path/to/site git pull origin master@endtask编写任务执行完上面的步骤后,就可以编写部署任务了。 简单一些的部署,在上面的基础上进行修改、添加命令即可,如下@servers(['web' => 'user_name@ip_path'])@task('deploy') cd /path/to/site git pull origin master composer install --no-dev@endtask复杂一些可以声明变量,以及使用 story,将多个 task 进行拆分,如下@servers(['web' => 'user_name@ip_path'])@setup$path = '/path/to/site';@endsetup@story('deploy')gitcomposer@endstory@task('git')cd {{ $path }}git pull origin master@endtask@task('composer')composer install --no-dev@endtask如果用了 Laradock,可以使用这样的命令 docker exec -u=laradock laradock_workspace_1 bash -c 'cd path && composer install --no-dev'执行使用 envoy run deploy 执行即可。注意要将 Envoy.blade.php 文件加入 .gitignore 防止泄漏重要信息。 ...

September 8, 2019 · 1 min · jiezi

Laracon-2019-第一天亮点-Laravel-6-和-Vapor

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...第一天的Laracon已经结束,有许多嘉宾进行了演讲!真是充满了精彩的演讲,精彩的人和新闻的一天! 集锦: Laravel 社区Justin Jackson 关于心理健康的演讲Laravel 6 和 新的品牌Vapor*社区整个社区的生态环境是十分棒的, 这里的人超级友好跟热情,而且已经开启了很多新的问题和讨论过的话题。 空气中弥漫着合作共赢的气息, 社区成员愿意换帮互助,分享资料,构建开源项目和共度美好的时光。 *Justin 的谈话我会说这段谈话在本次活动中得到了很多的关注。 他所提到的一些主要的内容: 「你采取的每一个行动,都会为 你想成为的人 投上一票」 James Clear「我们每个人都背负着心理包袱,如果未能够及时发现它,它可能会导致我们陷入破坏性的行为的状态」 Jerry Colonna 重要提示: 1- 寻求专业的帮助。\2- 承担你生命的所有权。\3- 反复的,做一些对你和他人有益的事情。\4- 摆脱你的坏习惯。\5- 迷失自我 在技术会议上听到心理健康讲座并不常见。但对于这项倡议的热烈掌声,让我相信这对人们的健康至关重要。 *Laravel 6 & 新类型将于 8 月发布。新的全职后端开发人员将于下周加入该团队。新 Logo。新官网。 *Vapor"令人难以置信的简单的扩大你的规模."Laravel Vapor 是由 AWS 驱动,可以对 Laravel程序进行无服务器部署的一项服务。使用 Vapor 部署你的 Laravel项目你会深深的爱上这种简便快捷的无服务。 主要特点 购买一个许可即可创建无限的团队和项目临时和正式域名执行部署简单的命令通过图形化界面回滚零宕机时间简单的维护模式环境变量管理很多有用的统计指标通过 email 和 Slack 告警日志查看数据库管理使用 DynamoDB 或 Redis 自动缓存Serverless 和 自动伸缩队列处理还有更多特性...

September 8, 2019 · 1 min · jiezi

扩展推荐-spatieLaravelpermission-Laravel-应用中的角色和权限控制

文章转发自专业的Laravel开发者社区,原始链接:https://learnku.com/laravel/t...将用户与角色进行关联这个包允许你在数据库中管理用户的权限和角色。 当你安装了扩展包之后你就可以这样做: // 给用户添加一个权限$user->givePermissionTo('edit articles');// 通过角色添加权限。$user->assignRole('writer');// 给角色添加一个权限$role->givePermissionTo('edit articles');如果你给单个用户添加了多个守卫(guard),扩展包也可以处理的很好,每一个分配给用户的守卫都有它自己的权限和角色,阅读 using multiple guards章节可以看见更多的信息。 因为所有的权限将注册在Laravel's gate上,所以你可以调用 Laravel 默认的 'can' 方法来测试用户是否有权限: $user->can('edit articles');Spatie 是一个位于 Antwerp, Belgium的web设计机构。你可以在我们的官网找到所有的开源项目。 安装Laravel这个包可以在 Laravel 5.4或更高版本中使用,如果你使用的是旧版本的Laravel,可以切换到 这个包的 v1 分支 去使用。 你可以通过 composer 去安装这个包: composer require spatie/laravel-permission在 Laravel 5.5 中 service provider 会自动注册,旧版本的Laravel中你需要像以下这样自行添加到 config/app.php 中: 'providers' => [ // ... Spatie\Permission\PermissionServiceProvider::class,];你可以使用以下命令发布 migration : php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"如果你在 User 模型中使用 UUIDs 或 GUIDs 你可以修改 create_permission_tables.php migration 并替换 $table->morphs('model'): $table->uuid('model_id');$table->string('model_type');migration发布后,您可以通过运行以下命令来创建角色和权限表: ...

September 7, 2019 · 7 min · jiezi

laravelmix配置vue的懒加载组件

larave-mix version: v4.1.2 安装依赖yarn add babel-plugin-syntax-dynamic-import --save-devyarn add babel-plugin-dynamic-import-webpack --save-dev.baberc增加: "plugins": [ ["syntax-dynamic-import"] ]webpack.config.js增加: mix.config.webpackConfig.output = { chunkFilename: 'js/[name].bundle.js', publicPath: 'public/dist/js',};引入组件改为://Vue.component('post-content-vue', require('../components/PostContent'));PostContent = ()=>import(/* webpackChunkName: "post-content" */'../components/PostContent');Vue.component('post-content-vue', PostContent);Enjoy.

August 20, 2019 · 1 min · jiezi

Laravel日志文件写入失败permission-denied

用过Laravel的小伙伴一开始安装完框架后可能都遇到过daily 日志文件写入失败的问题,接下来我们就来详细说下日志文件写入失败的原因以及对应的解决方案。 在讲这个问题之前可能需要简单介绍下Linux系统下的文件的Ownership和Permission。 Ownership UserUser是文件的所有者,默认情况下,用户创建了一个文件,该文件的所有者就是该用户。 Group一个用户组能包含多个用户,所有属于这个组的用户都有相同的权限来访问文件。假设你有一个项目,很多用户都需要访问这个项目文件的权限,你不需要手动赋予这些用户所有权限,你只需要把这些用户加到一个组里面,赋予这些组有访问文件的权限,这样一来就仅仅只有组里面的成员能对文件进行读写操作。 Other任何其他的用户都能访问文件,因此,给Other用户赋予权限,相当于所有用户都拥有这个权限。 Permission 在 UNIX/Linux 系统中每一个文件和目录都有3中权限,以下就是对三个所有者的讨论。 Read:这个权限赋予你打开和读取文件的权限。拥有目录的读权限,你能列出其内容。Write:拥有了读权限,你能修改文件的内容。拥有了目录的写权限,你能添加、移除以及重命名该目录下的文件。考虑一种场景,当你拥有文件的写权限,但是没有文件存储目录的写权限,你还是能修改文件的内容,但不能重命名、移动以及移除目录下的文件。Execute:在Windows系统中,一个可执行的程序通常都有.exe后缀,你能很方便的运行它。在 UNIX/Linux 中,除非被赋予可执行权限,否则你将不能运行该程序。如果未授权可执行权限,你让然可以看并修改程序代码(被授予读和写权限),但是无法运行它。 <div style="text-align:center;font-size:12px">linux下文件信息的显示截图</div> <div style="text-align:center;font-size:12px">linux下目录的信息显示截图</div> 以上的截图显示了一个文件和文件夹的信息,我们可以看到: r 代表可读, w 代表可写, x 代表可执行。第一位文件显示 - ,文件显示 d 。上面第一张图片, rw-rw-r-— 中。第一组 rw- 表示文件的所有者对文件有可读、可写、不可执行的权限。第二组 rw- 表示文件所属的组内用户对该文件有可读、可写、不可执行的权限。第三组 r-— 表示其他任何用户对该文件有可读、不可写、不可执行的权限。rw-rw-r-- 用二进制表示为 664 ,每一位如有权限则为 1 ,否则为 0 ,第一个三位 rw- 用二进制表示为 110 转化为十进制就是 6,后面两组依次类推,最后得到 664 。上面第一张图片的 dior www-data 表示该文件的所有者是 dior 用户,文件属于 www-data 组。我们知道很多应用系统中的日志是写文件的,且是以日期来命名文件的。所以第一次创建日志的用户就显得尤为重要,如果文件创建的 Onwer和 Group 不对,其他的用户触发写入日志文件就会失败。 接下来我们讨论下有多少种不同的用户可能创建日志文件: Crontab中执行的定时任务,跟创建 Crontab 的用户有关,此时创建的文件 Owner 和 Group 值分别是该用户以及默认的 Group 。一些常驻的后台进程,比如Laravel中的 queue work ,此时创建的日志文件 Owner 和 Group 值分别是执行该进程的用户以及所属的默认 Group 。正常用户访问网站产生的日志文件,此时创建的日志文件的 Owner 和 Group 都是 www-data , www-data 用户是web服务器默认的用户。由以上的分析,我们大概已经找到了解决问题的方法。 ...

August 18, 2019 · 1 min · jiezi

这是一份儿PHPer需要的远程开发环境不依赖Windows拥抱Linux

一般情况,开发者多使用Windows系统,PHPStorm、VSCode等软件让我们离不开Windows,但是,但是多数开发者更倾向于在Linux上部署环境。那么这一份教程就诞生了。(MacOS用户可以绕行)工具PHPStormUbuntu 16.04准备工作在Windows系统上安装PHPStorm和VM虚拟机,在虚拟机中安装Ubuntu系统。 在Ubuntu安装lnmp(Linux+Nginx+MySQL+PHP)集成环境 wget http://soft.vpser.net/lnmp/lnmp1.6.tar.gz -cO lnmp1.6.tar.gz && tar zxf lnmp1.6.tar.gz && cd lnmp1.6 && ./install.sh lnmp远程部署代码打开PHPStorm,选择Create New Project from Existing Files 选择从远程服务器ftp同步项目 输入项目名,并选择要同步到本地的项目路径 自动上传操作选择如下,当你Ctrl+S时,PHPStorm会帮你上传当前修改的文件到服务器。这样会相当方便。 选择新建远程服务器 填写项目名,Type选择SFTP,填写服务器IP、用户名、密码以及远程项目所在的路径。 //linux下查看ip命令(不是Windows的ipconfig)ghost@ghost-virtual-machine:~$ ifconfig 直接点finish,PHPStorm会自动同步远程服务器的代码。 远程debug安装xdebug扩展下载、编译xdebug wget http://www.xdebug.org/files/xdebug-2.2.3.tgztar xzf xdebug-2.2.3.tgzcd xdebug-2.2.3/usr/bin/phpize./configure --with-php-config=/usr/local/php/bin/php-configmakemake install查看php安装路径下的lib 库目录是否生成了xdebug.so文件。(我的目录:/usr/local/php/lib/php/extensions/xdebug.so) 然后配置/usr/local/php/etc/php.ini文件,需要注意的是xdebug是zend扩展,zend_extension= "xdebug.so",而不是extension= "xdebug.so"。 [xdebug]zend_extension= "xdebug.so"xdebug.profiler_enable = onxdebug.default_enable = onxdebug.trace_output_dir="/tmp/xdebug"xdebug.trace_output_name = trace.%c.%pxdebug.profiler_output_dir="/tmp/xdebug"xdebug.profiler_output_name="cachegrind.out.%s"xdebug.remote_enable =1xdebug.remote_handler = "dbgp"xdebug.remote_host = 10.0.100.236 //本机的ip,不是虚拟机或者远程服务器的ipxdebug.remote_mode = "req"xdebug.remote_port = 9001如果不知道本机的ip或本机为动态ip,需要加入xdebug.remote_connect_back,将其设置为1,此时xdebug.remote_host会失效。 ...

July 14, 2019 · 1 min · jiezi

Lumen-实现-SQL-监听

首发于:我的博客之前 Lumen 框架从 5.6 升级到 5.7。发现 laravel-sql-logger 包不能正常纪录日志了。进行排查,发现是 Lumen 框架没有对 DB 类型注入 event 对象,导致不能正常对其进行SQL监听。 那么解决方案也非常简单。 // file: bootstrap/app.php$app["db"]->connection()->setEventDispatcher($app["events"]); // 在下面的注册前加入这一行即可$app->register(Mnabialek\LaravelSqlLogger\Providers\ServiceProvider::class);但是这也让我对如何实现SQL纪录产生了兴趣。接下来,我们就具体了解一下如何实现SQL监听。 我们知道在Larvel上非常简单。只需要如下方法即可对其进行SQL监听: namespace App\Providers;use Illuminate\Support\Facades\DB;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ /** * 启动应用服务 * * @return void */ public function boot() { DB::listen(function ($query) { // $query->sql // $query->bindings // $query->time }); } //...}但是在 Lumen 上这种办法是没有办法使用的。Lumen有一些自己的调试SQL的方法,但是这些并不是我们想要的。所以我们只能自己写监听事件。 具体的解决方案是,我们首先创建一个Listener文件。 // file: app\Listeners\QueryListener.phpnamespace App\Listeners;use Illuminate\Database\Events\QueryExecuted;class QueryListener{ /** * Create the event listener. * * @return void */ public function __construct() { // } /** * Handle the event. * * @param ExampleEvent $event * @return void */ public function handle(QueryExecuted $event) { dd($event); // 此处直接对其进行打印 }}接下来我们直接对其进行注册 ...

July 12, 2019 · 3 min · jiezi

如何使用-PHP-Storm-进行优雅的项目开发

前言PHP Storm 这个开发工具,很多 phper 应该有所而为,甚至也有不少人使用其作为生产工具,但是很多人都没有最大限度的使用它,本文就来总结一些优雅开发的小技巧。 开发环境开发工具在看这篇文章之前,我想你应该已经安装好了 PHP Storm,如果没有你也可以尝试去官网下载页面,进行下载安装使用,关于许可,不在本文的讨论范围内,你可以使用以下方式获取免费许可。 教育许可GitHub 活跃开发者Microsoft MVP虽然有很多特殊方式可以激活,但是还是倡导使用正版软件。请尽量使用原版英文界面,不要安装汉化补丁。 PHP在此,我希望你最好能够安装最新的 PHP 发行版(7.3.x),进行开发和项目部署。 进入主题看到这里,我希望你已经准备好了上面所提到的,那么我们就开始解决开发中的一些问题。 Material-Theme-UI 这是我的默认开发界面,使用的是内置主题,Solarized Light ,开发工具内置的主题默认只会改变代码区域的主题色,像项目的索引,这些地方都不会变(当然 这些都可以去手动改)。而且,默认的图标的辨识度也不是很高。这里可以安装一个主题 Material Theme UI 注意看左侧,Project 处的索引,的项目图标有了明显的变化,这样当我们在同一个目录下有不同类型的文件时,就能通过图标很快的辨识出来。除此之外还有常见的 Model、util 、log 、public 、vendor 、config、static 、Middleware 、 Controller都会有特殊的图标用来提高辨识度,相比默认的要好的多。 .ignore看名字,就知道是用来创建忽略文件的,当我们创建一个新项目时,一些东西是不需要提交到版本管理库的,比如 composer 的 vendor 目录、node.js 的 node_modules 等等。这些目录通常都是不需要提交道版本管理库的,前端开发会有更多各种各样的这时候我们就可以用这个工具来快速创建。 可以看到,我们可以通过选择项目模板,来高效,快速准确地创建忽略文件。而且,当我们需要手动忽略某个目录时,也不需要手动去编辑 .gitignore 文件,只需要右键目录,选择对应的操作即可。 其他插件.env files support这个插件使用来支持 env 方法中提示的 PHP composer. json support用于 composer.json 中的一些提示根据不同框架LaravelThinkPHP5 Plugin...因为我只用过这两个框架相关的插件,其他的就不列举了。因为 Laravel 插件安装还是比较繁琐的,虽然繁琐,但是真的很强大,至于安装,可以参考这篇文章 送给Laravel 开发者Laravel IDE Helper 还有一个功能,很少有文章提到的,就是 模型注释。都知道 Laravel 是支持 ORM 的,但是,当我们直接通过对象获取模型的某个属性时,IDE 可能会提示你未定义的属性,但是这并不影响使用,只是开发过程中看起来比较糟糕,就像下面这样。出现了异常,但是我们数据库是有这个字段的,而对象上没有,但是因为我们继承了 根模型 Model ,上有 __get() 方法,所以在 id 下面显示了 点 来引起我们的注意,虽然这样代码对我们程序运行时没有影响,但是开发看起来却不是那么的友好。当我们使用模型注释后,就会为我们的每个模型对象自动生成如下的注释信息。 ...

July 12, 2019 · 2 min · jiezi

如何解决-larave-在-mysql-8-报错-SQLSTATEHY000-2054

如何解决 larave 在 mysql 8 报错 SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client (SQL: select from information_schema.tables where table_schema = and table_name作为一个好奇猿,最近新项目中使用了 MySQL 8.0 版本,安装过程都很顺畅,满心期待着周五的时候,结果上线时报了上面的错。原因在于 MySQL 8.0 验证插件做了变动,具体可以参考 https://dev.mysql.com/doc/rel... 具体解决步骤可以参考如下步骤 (让我们手拉手,摸着石头过河): 修改 MySQL 配置文件中的验证插件类型并重启 MySQL [mysqld]default_authentication_plugin= mysql_native_password如果之前已经创建过对应的 user,建议使用如下 SQL 重新创建, 其中 {} 的内容大家可以根据实际情况进行替换 CREATE USER '{user}'@'{localhost}' IDENTIFIED WITH mysql_native_password BY '{password}'; 最后推荐有课学微信公众号,有课学是一站式的课程返现 + 好课推荐平台。希望大家都能【学好课,有课学,学有所获】。

July 12, 2019 · 1 min · jiezi

soarPHP-SQL-语句优化器和重写器的-PHP-扩展包-方便框架中-SQL-语句调优

soar-php 是一个基于小米公司开源的 soar 开发的 PHP 扩展包,方便框架中 SQL 语句调优。 项目链接https://github.com/guanguans/soar-phphttps://github.com/guanguans/think-soar框架中使用[x] ThinkPHP[ ] Symfony[ ] Laravel[ ] Lumen[ ] Yii2[ ] Slim环境要求PHP >= 5.6ext-pdoext-json安装$ composer require guanguans/soar-php --dev使用下载 XiaoMi 开源的 SQL 优化器 soar,更多详细安装请参考 soar install# macOS$ wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.darwin-amd64# linux$ wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.linux-amd64# windows$ wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.windows-amd64# 用其他命令或下载器下载均可以初始化配置,更多详细配置请参考 soar config方法一、运行时初始化配置<?phprequire_once __DIR__.'/vendor/autoload.php';use Guanguans\SoarPHP\Soar;$config = [ // 下载的 soar 的路径 '-soar-path' => '/Users/yaozm/Documents/wwwroot/soar-php/soar.darwin-amd64', // 测试环境配置 '-test-dsn' => [ 'host' => '127.0.0.1', 'port' => '3306', 'dbname' => 'database', 'username' => 'root', 'password' => '123456', ], // 日志输出文件 '-log-output' => './soar.log', // 报告输出格式: 默认 markdown [markdown, html, json] '-report-type' => 'html',];$soar = new Soar($config);方法二、配置文件初始化配置vendor 同级目录下新建 .soar.dist 或者 .soar,内容参考 .soar.example,例如: ...

July 9, 2019 · 2 min · jiezi

一文读懂TOGAF企业架构

TOGAF ®,由The Open Group的标准,是一个成熟的企业架构方法和框架由世界领先的组织使用,以提高业务效率。它是最突出和最可靠的企业架构标准,可确保企业架构专业人员之间的一致标准,方法和通信。精通TOGAF标准的企业架构专业人员享有更高的行业信誉,工作效率和职业机会。TOGAF帮助从业者避免陷入专有方法,更有效地利用资源,实现更高的投资回报。 为何选择TOGAF?IT架构需要密切反映组织的业务目标。实际上,应该使用特定的技术(业务场景)来确保IT架构师正确理解业务目标,并反映在使用TOGAF开发的IT架构中。 以下是我们应该采用TOGAF ADM进行架构开发的原因: 一种全面的通用方法与其他框架互补,不与其他框架竞争在市场上广泛采用可以满足组织和行业的需求可免费获得永久许可供应商,工具和技术中立的开放标准避免重新发明轮子业务IT一致性基于最佳实践可以参与框架的演变什么是TOGAF架构开发方法(ADM)?架构开发方法(ADM)用于开发满足组织业务和信息技术需求的企业架构。TOGAF ADM是大量架构从业者为实现以下目的而不断贡献的结果: 它描述了一种开发和管理企业体系结构生命周期的方法,并构成了TOGAF的核心。它可以根据组织的需求进行定制,然后用于管理体系结构规划活动的执行。TOGAF和ArchiMateArchiMate是Open Group引入的建模标准。它提供了一组丰富的建模符号和概念,支持在域内和域之间一致地建模企业架构。 由于TOGAF和ArchiMate都是由Open Group维护的标准,它们都用于企业架构开发,很多人在它们之间感到困惑,提出诸如“TOGAF和ArchiMate之间有什么区别?”,“TOGAF vs ArchiMate?”之类的问题, TOGAF框架和ArchiMate建模语言均由The Open Group维护。TOGAF 9.1和ArchiMate 2.1或更高版本协同工作,是EA开发的兼容和补充。虽然TOGAF ADM是一个可用于开发和实施企业系统,流程和结构的EA框架,但ArchiMate可用作可视建模语言,可用于创建EA描述。 重申ArchiMate标准是建模语言而非框架是很重要的。ArchiMate语言广泛用于开发可视化EA模型,通常与TOGAF ADM一起使用。此外,TOGAF和ArchiMate标准可以组合在一起,提供一组可用于建模不同体系结构的视点。 ArchiMate语言由ArchiMate核心语言组成,其中包括业务,应用程序和技术层,以及构建体系结构的策略和动机以及实现和迁移的元素。 下图显示了ArchiMate语言如何与TOGAF架构开发方法(ADM)阶段相关的简化映射。 ArchiMate核心代码ArchiMate层可以对TOGAF定义的体系结构域进行建模。 该业务,应用和技术层支持业务,信息系统和技术架构领域由TOGAF框架中定义的描述,以及它们的相互关系。 战略与动机延伸战略和动机扩展可以实现利益相关者的建模,变革的驱动因素,业务目标,原则和要求。 ArchiMate语言中的策略和激励元素可用于支持TOGAF ADM 的需求管理,初步和架构愿景阶段,这些阶段建立了高级业务目标,架构原则和初始业务需求。它们也与TOGAF ADM的架构变更管理阶段相关,因为该阶段涉及不断变化的需求。 实施和迁移扩展实施和迁移扩展支持项目组合管理,差距分析以及过渡和迁移规划的建模。 ArchiMate语言的实现和迁移元素通过TOGAF ADM的机会和解决方案,迁移规划和实施治理阶段支持体系结构的实施和迁移。 TOGAF ADM生命周期 - 迭代ADM支持三个级别的迭代概念: 在ADM周围循环:ADM以循环方式呈现,表明一个架构工作的完成直接进入架构工作的后续阶段。 在阶段之间进行迭代:TOGAF描述了跨阶段迭代的概念(例如,在完成技术架构时返回到业务架构)。 围绕单个阶段循环:TOGAF支持在单个ADM阶段内重复执行活动,作为详细描述架构内容的技术。 TOGAF ADM在ADM过程的应用过程中,根据ADM提供的相位目标,根据一些输入和步骤产生许多输出。 例如: 流程架构要求项目计划项目合规评估等等为了以一致和结构化的方式整理和展示这些主要的工作产品,TOGAF定义了一个结构模型,用于放置它们。 ADM输入和输出TOGAF从每个阶段提供了许多输入和输出可交付成果: 这些是建议,不需要完全遵循生成的每个可交付成果应进行版本化以指示何时发生更改显示的版本编号也是一个建议,无需遵循交付合同规定的工作产品,然后由利益相关者正式审查,同意和签署。它通常在项目完成时归档,或者作为参考模型转换为Architecture Repository ADM初步阶段创建体系结构功能所需的准备和启动活动,包括TOGAF的定制和体系结构的定义 输出可交付成果:架构原则架构库业务原则,业务目标和业务驱动因素企业架构的组织模型要求架构工作量身定制的架构框架ADM阶段A:架构愿景架构开发周期的初始阶段。它包括有关定义体系结构开发计划范围,识别利益相关者,创建体系结构愿景以及获得批准以继续体系结构开发的信息 输出可交付成果:架构原则架构路线图架构愿景业务原则,业务目标和业务驱动因素能力评估沟通计划架构工作声明量身定制的架构框架ADM阶段B:业务架构业务架构:开发业务架构以支持商定的架构愿景 输出可交付成果:架构定义文档架构原则架构要求规范架构路线图业务原则,业务目标和业务驱动因素架构工作声明ADM阶段C:信息系统架构信息系统架构:开发信息系统架构以支持商定的架构愿景 架构定义文档架构原则架构要求规范架构路线图架构工作声明ADM阶段D:技术架构技术架构:技术架构的发展,以支持商定的架构愿景 输出可交付成果:架构定义文档架构原则架构要求规范架构路线图架构工作声明ADM阶段E:机遇与解决方案机遇与解决方案为前几个阶段定义的架构进行初步实施计划和交付工具的识别 输出可交付成果:架构定义文档架构要求规范架构路线图架构愿景能力评估实施和迁移计划架构工作声明ADM阶段F:迁移计划迁移规划通过最终确定详细的实施和迁移计划,阐述如何从基准迁移到目标体系结构 架构构建基块架构定义文档架构要求规范架构路线图变更请求实施和迁移计划实施治理计划要求架构工作架构工作声明ADM阶段G:实施治理实施治理提供了对实施的架构监督 输出可交付成果:改变请求合规评估解决方案构建块架构工作声明ADM阶段H:架构变更管理架构变更管理建立了管理新架构变更的程序。需求管理检查整个ADM中管理架构需求的过程 摘要ADM是一种综合的通用方法 它建议了开发体系结构所涉及的各个阶段和步骤的顺序这是一种迭代方法它利用了TOGAF的其他部分来获取资产和流程它可以与其他框架的其他可交付成果一起使用以下是每个开发阶段的TOGAF ADM概述,如下图所示: ...

July 9, 2019 · 1 min · jiezi

????-Hyperf-多个组件-v104-更新-企业级的-PHP-微服务协程框架

v1.0.4 更新内容本次更新涉及以下组件,主要增加了 Swoole 4.4 的支持及部分组件的功能强化,以及修复了一些 Bug hyperf/async-queue hyperf/command hyperf/config hyperf/constants hyperf/consul hyperf/contract hyperf/database hyperf/db-connection hyperf/di hyperf/dispatcher hyperf/framework hyperf/http-server hyperf/pool hyperf/redis hyperf/rpc-client hyperf/service-governance hyperf/utils hyperf/websocket-server 新增#140 支持 Swoole v4.4.0.#152 数据库连接在低使用率时连接池会自动释放连接#163 constants 组件的AbstractConstants::__callStatic 支持自定义参数变更#124 DriverInterface::push 增加 $delay 参数用于设置延迟时间, 同时 DriverInterface::delay 将标记为弃用的,将于 1.1 版本移除#125 更改 config() 函数的 $default 参数的默认值为 null.修复#110 #111 修复 Redis::select 无法正常切换数据库的问题#131 修复 middlewares 配置在 Router::addGroup 下无法正常设置的问题#132 修复 request->hasFile 判断条件错误的问题#135 修复 response->redirect 在调整外链时无法正确生成链接的问题#139 修复 ConsulAgent 的 URI 无法自定义设置的问题#148 修复当 migrates 文件夹不存在时无法生成迁移模板的问题#169 修复处理请求时没法正确处理数组类型的参数#170 修复当路由不存在时 WebSocket Server 无法正确捕获异常的问题移除#131 移除 Router options 里的 server 参数关于 HyperfHyperf 是基于 Swoole 4.3+ 实现的高性能、高灵活性的 PHP 协程框架,内置协程服务器及大量常用的组件,性能较传统基于 PHP-FPM 的框架有质的提升,提供超高性能的同时,也保持着极其灵活的可扩展性,标准组件均均基于 PSR 标准 实现,基于强大的依赖注入设计,保证了绝大部分组件或类都是 可替换 与 可复用 的。   框架组件库除了常见的协程版的 MySQL 客户端、Redis 客户端,还为您准备了协程版的 Eloquent ORM、JSON RPC 服务的及客户端、GRPC 服务端及客户端、Zipkin (OpenTracing) 客户端、Guzzle HTTP 客户端、Elasticsearch 客户端、Consul 客户端、ETCD 客户端、AMQP 组件、Apollo 配置中心、阿里云 ACM 应用配置管理、基于令牌桶算法的限流器、通用连接池、熔断器、Swagger 文档生成 等组件,省去了自己实现对应协程版本的麻烦,Hyperf 还提供了 基于 PSR-11 的依赖注入容器、注解、AOP 面向切面编程、基于 PSR-15 的中间件、自定义进程、基于 PSR-14 的事件管理器、Redis/RabbitMQ 消息队列、自动模型缓存、基于 PSR-16 的缓存 等非常便捷的功能,满足丰富的技术场景和业务场景,开箱即用。 ...

July 9, 2019 · 1 min · jiezi

Snow简单易用的Go语言业务框架

项目地址中文文档changelogSnowSnow是一套简单易用的Go语言业务框架,整体逻辑设计简洁,支持HTTP服务、队列调度和任务调度等常用业务场景模式。 Goals我们致力于让PHPer更方便地切入到Go语言开发,在业务框架选择上贴合PHP主流框架的设计思想,以更低的学习成本快速熟悉框架,致力于业务逻辑的开发。 FeaturesHTTP服务:基于gin进行模块化设计,简单易用、核心足够轻量;支持平滑重启;任务调度:基于cron进行模块化设计,简单易用;队列调度:基于自研的队列调度服务worker,通过Queue接口化,解耦队列调度与底层队列驱动;支持平滑关闭;Cache: 通用的接口化设计,框架实现了redis作为缓存底层驱动,支持可扩展;Database: 使用成熟的ORM库,有丰富的数据库驱动支持和特性;Queue: 通用的接口化设计,框架实现了redis、alimns作为队列底层驱动,支持可扩展;Config: 采用toml语义化的配置文件格式,简单易用;Logger: 基于logrus进行封装,内嵌上下文通用数据采集和trace_id追踪;Request and Response:定义输入和输出数据实体格式;Curl: 简单易用的Curl请求库;Quick startRequirementsGo version>=1.12 Installationcd $GOPATH/srccd my-github/my-spacegit clone git@github.com/qit-team/snow.git my-projectcd my-projectsh build/shell/replace.sh my-github/my-space/my-projectBuild & Runsh build/shell/build.shbuild/bin/snowTest democurl "http://127.0.0.1:8000/hello" #返回json串输出Documents中文文档changelog

July 8, 2019 · 1 min · jiezi

每日Scrum中的3个重要问题是什么

这是整个团队简洁地同步每个人的个人进度(Burn down chart)与迭代的Sprint,特征或故事点估计的机会。换句话说,站立是一个状态更新会议,时间限制为十五分钟,下面有三个基本问题。 你昨天做了什么?你今天会做什么?是否有任何阻碍者或障碍阻碍您开展工作?一个强大的Scrum软件,支持Scrum项目管理。它具有Scrum工具,如用户故事地图,产品积压管理,sprint积压管理,任务管理,日常scrum会议,sprint计划工具,sprint审查工具,sprint回顾工具,burndown,障碍,利益相关者和团队管理。 每日Scrum中3个问题的目的在每日的Scrum是一个Sprint期间重点检查和适应的会议。它旨在快速通知每个人整个团队的情况。这不是详细的状态会议。下面列出的是每日Scrum会议的一些好处: 同步团队的工作。识别并消除发展障碍适应每日计划和Sprint Backlog。通过查看和更新燃尽图来跟踪进度[](https://www.visual-paradigm.c...改善团队参与和协作。什么是每日Scrum?持续时间:约15分钟 参与者: Scrum Master,Scrum团队和产品负责人 规则和指南: 在同一时间和地点开始工作日Scrum Master是会议的推动者会议与整个团队一起举行,以便不会延长会议超过15分钟Scrum团队的每个成员都应该回答上面提到的三个问题Scrum团队的每个成员都应该花费不到2到3分钟的时间来回答上述问题这是简单易懂的,但并不是团队用一个声音说话。它还可以快速降级为状态会话,并且不会为sprint backlog的进度带来真正的清晰度。 每日站立会议

July 8, 2019 · 1 min · jiezi

Laravel扩展包开发

Laravel扩展包开发

July 4, 2019 · 1 min · jiezi

如何理解-Laravel-和-ThinkPHP-5-中的服务容器与注入

从文档说起很多人一开始看到官方的文档,无论是 Laravel 还是 ThinkPHP ,看完都是一头雾水,不求甚解。甚至都是直接跳过去,不看,反正我也不一样用得到这么高端的东西,如果在短时间内有这个念头很正常,尤其是习惯了 ThinkPHP 3 的使用者,相对引入的理念比较前沿,如果你在长时间内都不去考虑去理解,那就要看你自己的职业规划了。接下来就来一起看一下,细细追品。 从 Laravel 开始从 Laravel 的文档中看到有 bind 、 singleton 以及 instance ,这三个常用方法,接下来就一一解答。 实际应用假设我们有这样一个场景,当我们用户在进行注册时,我们需要向用户手机发送一条短信验证码,然后当用户收到验证码后在注册表单提交时还需要验证验证码是否正确。 这个需求看起来非常容易实现,对吧? 当我们拿到短信平台的开发文档后,我们只需要写出两个方法。send 和 check 分别用来发送验证码和校验验证码,下面就在不用容器的情况下来写一下伪代码。 MeiSms.php<?phpnamespace App\Tools;class MeiSms{ public function send($phone) { $code = mt_rand(1e3, 1e4 - 1); // TODO ... 通过接口发送 // 存放验证码到 Redis $cacheManager = cache(); // 设定 5 分钟失效 $cacheManager->set('sms:' . $phone, $code, 5 * 60); return true; } public function check($phone, $code) { $cacheManager = cache(); return $cacheManager->get('sms:' . $phone) === $code; }}很容易,不是吗? ...

July 3, 2019 · 4 min · jiezi

Laravel-中使用-swoole-项目实战开发案例二-后端主动分场景给界面推送消息

最近使用 swoole 做了项目,里面设计推送信息给界面前端,和无登陆用户的状态监控,以下是本人从中获取的一点心得,有改进的地方请留言评论。 需求分析我们假设有一个需求,我在后端点击按钮1,首页弹出“后端触发了按钮1”。后端点了按钮2,列表页弹出“后端触发了按钮2”。做到根据不同场景推送到不同页面。 代码思路Swoole fd客户端浏览器打开或者刷新界面,在swoole服务会生成一个进程句柄 fd ,每次浏览器页面有打开链接websocket的js代码,便会生成,每次刷新的时候,会关闭之前打开的 fd,重新生成一个新的,关闭界面的时候会生成一个新的。swoole的 fd生成规则是从1开始递增。 Redis Hash存储 fd我们建立一个key为swoole:fds redis哈希类型数据,fd 为hash的字段,每个字段的值我们存储前端websocket请求的url参数信息(根据业务复杂度自己灵活变通,我在项目中会在url带上sessionId)。每次链接打开swoole服务的时候我们存储其信息,每次关闭页面时候我们清除其字段。在redis存储如下 触发分场景推送在界面上当进行了触发操作的时候,通过后台curl请求swoole http服务,swoole http服务根据你向我传递的参数分发给对应的逻辑处理。如curl请求127.0.0.1:9502page=back&func=pushHomeLogic&token=123456 我们可以根据传入的func参数,在后台分发给对应逻辑处理。如分发给pushHomeLogic方法。在其里面实现自己的逻辑。为防止过多的if else 以及 foreach 操作,我们采用的是闭包,call_user_func等方法实现如下 public function onRequest($request,$response) { if ($this->checkAccess("", $request)) { $param = $request->get; // 分发处理请求逻辑 if (isset($param['func'])) { if (method_exists($this,$param['func'])) { call_user_func([$this,$param['func']],$request); } } } }// 往首页推送逻辑处理 public function pushHomeLogic($request) { $callback = function (array $aContent,int $fd,SwooleDemo $oSwoole)use($request) { if ($aContent && $aContent['page'] == "home") { $aRes['message'] = "后端按了按钮1"; $aRes['code'] = "200"; $oSwoole::$server->push($fd,xss_json($aRes)); } }; $this->eachFdLogic($callback); }完整代码swool脚本代码逻辑<?phpnamespace App\Console\Commands;use Closure;use Illuminate\Console\Command;use Illuminate\Support\Facades\Redis;class SwooleDemo extends Command{ // 命令名称 protected $signature = 'swoole:demo'; // 命令说明 protected $description = '这是关于swoole websocket的一个测试demo'; // swoole websocket服务 private static $server = null; public function __construct() { parent::__construct(); } // 入口 public function handle() { $this->redis = Redis::connection('websocket'); $server = self::getWebSocketServer(); $server->on('open',[$this,'onOpen']); $server->on('message', [$this, 'onMessage']); $server->on('close', [$this, 'onClose']); $server->on('request', [$this, 'onRequest']); $this->line("swoole服务启动成功 ..."); $server->start(); } // 获取服务 public static function getWebSocketServer() { if (!(self::$server instanceof \swoole_websocket_server)) { self::setWebSocketServer(); } return self::$server; } // 服务处始设置 protected static function setWebSocketServer():void { self::$server = new \swoole_websocket_server("0.0.0.0", 9502); self::$server->set([ 'worker_num' => 1, 'heartbeat_check_interval' => 60, // 60秒检测一次 'heartbeat_idle_time' => 121, // 121秒没活动的 ]); } // 打开swoole websocket服务回调代码 public function onOpen($server, $request) { if ($this->checkAccess($server, $request)) { self::$server->push($request->fd,xss_json(["code"=>200,"message"=>"打开swoole服务成功"])); } } // 给swoole websocket 发送消息回调代码 public function onMessage($server, $frame) { } // http请求swoole websocket 回调代码 public function onRequest($request,$response) { if ($this->checkAccess("", $request)) { $param = $request->get; // 分发处理请求逻辑 if (isset($param['func'])) { if (method_exists($this,$param['func'])) { call_user_func([$this,$param['func']],$request); } } } } // websocket 关闭回调代码 public function onClose($serv,$fd) { $this->redis->hdel('swoole:fds', $fd); $this->line("客户端 {$fd} 关闭"); } // 校验客户端连接的合法性,无效的连接不允许连接 public function checkAccess($server, $request):bool { $bRes = true; if (!isset($request->get) || !isset($request->get['token'])) { self::$server->close($request->fd); $this->line("接口验证字段不全"); $bRes = false; } else if ($request->get['token'] != 123456) { $this->line("接口验证错误"); $bRes = false; } $this->storeUrlParamToRedis($request); return $bRes; } // 将每个界面打开websocket的url 存储起来 public function storeUrlParamToRedis($request):void { // 存储请求url带的信息 $sContent = json_encode( [ 'page' => $request->get['page'], 'fd' => $request->fd, ], true); $this->redis->hset("swoole:fds", $request->fd, $sContent); } /** * @param $request * @see 循环逻辑处理 */ public function eachFdLogic(Closure $callback = null) { foreach (self::$server->connections as $fd) { if (self::$server->isEstablished($fd)) { $aContent = json_decode($this->redis->hget("swoole:fds",$fd),true); $callback($aContent,$fd,$this); } else { $this->redis->hdel("swoole:fds",$fd); } } } // 往首页推送逻辑处理 public function pushHomeLogic($request) { $callback = function (array $aContent,int $fd,SwooleDemo $oSwoole)use($request) { if ($aContent && $aContent['page'] == "home") { $aRes['message'] = "后端按了按钮1"; $aRes['code'] = "200"; $oSwoole::$server->push($fd,xss_json($aRes)); } }; $this->eachFdLogic($callback); } // 往列表页推送逻辑处理 public function pushListLogic($request) { $callback = function (array $aContent,int $fd,SwooleDemo $oSwoole)use($request) { if ($aContent && $aContent['page'] == "list") { $aRes['message'] = "后端按了按钮2"; $aRes['code'] = "200"; $oSwoole::$server->push($fd,xss_json($aRes)); } }; $this->eachFdLogic($callback); } // 启动websocket服务 public function start() { self::$server->start(); }}控制器代码<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;use Illuminate\Support\Facades\Redis;class TestController extends Controller{ // 首页 public function home() { return view("home"); } // 列表 public function list() { return view("list"); } // 后端控制 public function back() { if (request()->method() == 'POST') { $this->curl_get($this->getUrl()); return json_encode(['code'=>200,"message"=>"成功"]); } else { return view("back"); } } // 获取要请求swoole websocet服务地址 public function getUrl():string { // 域名 端口 请求swoole服务的方法 $sBase = request()->server('HTTP_HOST'); $iPort = 9502; $sFunc = request()->post('func'); $sPage = "back"; return $sBase.":".$iPort."?func=".$sFunc."&token=123456&page=".$sPage; } // curl 推送 public function curl_get(string $url):string { $ch_curl = curl_init(); curl_setopt ($ch_curl, CURLOPT_TIMEOUT_MS, 3000); curl_setopt($ch_curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt ($ch_curl, CURLOPT_HEADER,false); curl_setopt($ch_curl, CURLOPT_HTTPGET, 1); curl_setopt($ch_curl, CURLOPT_RETURNTRANSFER,true); curl_setopt ($ch_curl, CURLOPT_URL,$url); $str = curl_exec($ch_curl); curl_close($ch_curl); return $str; }}页面js代码后端控制页<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>后端界面</title> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"></head><body><button class="push" data-func="pushHomeLogic">按钮1</button><button class="push" data-func="pushListLogic">按钮2</button></body><script src="{{ asset("/vendor/tw/global/jQuery/jquery-2.2.3.min.js")}} "></script><script> $(function () { $(".push").on('click',function(){ var func = $(this).attr('data-func').trim(); ajaxGet(func) }) function ajaxGet(func) { url = "{{route('back')}}"; token = "{{csrf_token()}}"; $.ajax({ url: url, type: 'post', dataType: "json", data:{func:func,_token:token}, error: function (data) { alert("服务器繁忙, 请联系管理员!"); return; }, success: function (result) { }, }) } })</script></html>首页<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>swoole首页</title> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"></head><body><h1>这是首页</h1></body><script> var ws;//websocket实例 var lockReconnect = false;//避免重复连接 var wsUrl = 'ws://{{$_SERVER["HTTP_HOST"]}}:9502?page=home&token=123456'; function initEventHandle() { ws.onclose = function () { reconnect(wsUrl); }; ws.onerror = function () { reconnect(wsUrl); }; ws.onopen = function () { //心跳检测重置 heartCheck.reset().start(); }; ws.onmessage = function (event) { //如果获取到消息,心跳检测重置 //拿到任何消息都说明当前连接是正常的 var data = JSON.parse(event.data); if (data.code == 200) { console.log(data.message) } heartCheck.reset().start(); } } createWebSocket(wsUrl); /** * 创建链接 * @param url */ function createWebSocket(url) { try { ws = new WebSocket(url); initEventHandle(); } catch (e) { reconnect(url); } } function reconnect(url) { if(lockReconnect) return; lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 setTimeout(function () { createWebSocket(url); lockReconnect = false; }, 2000); } //心跳检测 var heartCheck = { timeout: 60000,//60秒 timeoutObj: null, serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.timeoutObj = setTimeout(function(){ //这里发送一个心跳,后端收到后,返回一个心跳消息, //onmessage拿到返回的心跳就说明连接正常 ws.send("heartbeat"); self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了 ws.close();//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次 }, self.timeout); }, this.timeout); }, header:function(url) { window.location.href=url } }</script></html>列表页面<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>swoole列表页</title> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"></head><body><h1>swoole列表页</h1></body><script> var ws;//websocket实例 var lockReconnect = false;//避免重复连接 var wsUrl = 'ws://{{$_SERVER["HTTP_HOST"]}}:9502?page=list&token=123456'; function initEventHandle() { ws.onclose = function () { reconnect(wsUrl); }; ws.onerror = function () { reconnect(wsUrl); }; ws.onopen = function () { //心跳检测重置 heartCheck.reset().start(); }; ws.onmessage = function (event) { //如果获取到消息,心跳检测重置 //拿到任何消息都说明当前连接是正常的 var data = JSON.parse(event.data); if (data.code == 200) { console.log(data.message) } heartCheck.reset().start(); } } createWebSocket(wsUrl); /** * 创建链接 * @param url */ function createWebSocket(url) { try { ws = new WebSocket(url); initEventHandle(); } catch (e) { reconnect(url); } } function reconnect(url) { if(lockReconnect) return; lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 setTimeout(function () { createWebSocket(url); lockReconnect = false; }, 2000); } //心跳检测 var heartCheck = { timeout: 60000,//60秒 timeoutObj: null, serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.timeoutObj = setTimeout(function(){ //这里发送一个心跳,后端收到后,返回一个心跳消息, //onmessage拿到返回的心跳就说明连接正常 ws.send("heartbeat"); self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了 ws.close();//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次 }, self.timeout); }, this.timeout); }, header:function(url) { window.location.href=url } }</script></html>界面效果后台控制点击按钮1 ...

July 2, 2019 · 5 min · jiezi

Redis-哨兵使用以及在-Laravel-中的配置

主从配置(master-slave)复制 redis 配置文件以开启多个 slavesudo cp /etc/redis.conf /etc/redis-6381.confsudo cp /etc/redis.conf /etc/redis-6382.conf 编辑 slave 配置文件,主要修改参数port 6381pidfile "/var/run/redis-6381.pid"logfile "/var/log/redis/redis-6381.log"slaveof 11.11.11.11 6381masterauth "123456" # 主从都保持一样的密码,且 master 的配置也需要这一行,在执行切换 master 的时候好像不会去添加这一行/usr/bin/redis-server /etc/redis.conf 通过配置启动 redis哨兵配置(sentinel)复制哨兵配置,这儿开启3个哨兵sudo cp /etc/redis-sentinel.conf /etc/redis-sentinel-26381.confsudo cp /etc/redis-sentinel.conf /etc/redis-sentinel-26382.conf 编辑哨兵配置文件,主要修改参数如下,根据具体情况配置port 26381pidfile "/var/run/redis-sentinel-26381.pid"logfile "/var/log/redis/redis-sentinel-26381.log"sentinel monitor mymaster 11.11.11.11 6379 2 #主节点别名为mymaster,后面是ip和端口,2代表判断主节点失败至少需要2个sentinel节点同意sentinel auth-pass mymaster 123456sentinel down-after-milliseconds mymaster 30000 #主节点故障30秒后启用新的主节点sentinel parallel-syncs mymaster 1 #故障转移时最多可以有1个从节点同时对主节点进行数据同步,数字越大,用时越短,存在网络和 IO 开销sentinel failover-timeout mymaster 180000 #故障转移超时时间180s:a 如果转移超时失败,下次转移时时间为之前的2倍;b 从节点变主节点时,从节点执行 slaveof no one 命令一直失败的话,当时间超过180S时,则故障转移失败;c 从节点复制新主节点时间超过180S转移失败/usr/bin/redis-sentinel /etc/redis-sentinel.conf 通过配置启动哨兵laravel 哨兵配置'default' => [ 'tcp://11.11.11.11:26379', 'tcp://11.11.11.11:26381', 'tcp://11.11.11.11:26382', //这3个都是sentinel节点的地址 'options' => [ 'replication' => 'sentinel', 'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'), //sentinel 'parameters' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), 'port' => env('REDIS_PORT', 6379), 'password' => env('REDIS_PASSWORD', null), //redis的密码,没有时写null 'database' => 0, ], ], ]

June 28, 2019 · 1 min · jiezi

laraveladmin-报错-Disk-admin-not-configured

记录下laravel-admin的一个小问题,在修改个人资料时,报错如下:Disk [admin] not configured, please add a disk config in config/filesystems.php.在config/filesystems.php中添加:'disks' => [ 'local' => [ 'driver' => 'local', 'root' => storage_path('app'), ], 'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), 'url' => env('APP_URL').'/storage', 'visibility' => 'public', ], 's3' => [ 'driver' => 's3', 'key' => env('AWS_KEY'), 'secret' => env('AWS_SECRET'), 'region' => env('AWS_REGION'), 'bucket' => env('AWS_BUCKET'), ], // 添加的代码 'admin' => [ 'driver' => 'local', 'root' => public_path('upload'), 'visibility' => 'public', 'url' => env('APP_URL').'/public/upload/', ],

June 27, 2019 · 1 min · jiezi

laravel-数据库迁移报错

问题描述(1)laravel 5.4或者更高版本 改变了默认的数据库字符集,现在utf8mb4包括存储emojis支持。如果你运行MySQL v5.7.7或者更高版本,则不需要做任何事情。(2)当你试着在一些MariaDB或者一些老版本的的MySQL上运行 migrations 命令时,你可能会碰到下面这个错误:Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes 【指定的键太长了,最大键的长是767bytes,因为laravel默认字符串长度是767bytes,所以要自己去手动配置。】解决方案<?phpnamespace App\Providers;// 导入Schema类use Illuminate\Support\Facades\Schema;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot() { // 在app/providers/AppServiceProvider.php中boot方法中加上 Schema::defaultStringLength(191); }}

June 27, 2019 · 1 min · jiezi

十个推荐使用的-Laravel-的辅助函数

array_dot()函数允许你将多维数组转换为使用点符号的一维数组。$array = [ 'user' => ['username' => 'something'], 'app' => ['creator' => ['name' => 'someone'], 'created' => 'today']];$dot_array = array_dot($array);// [user.username] => something, [app.creator.name] => someone, [app.created] => todayarray_get()函数使用点符号从多维数组中检索值。$array = [ 'user' => ['username' => 'something'], 'app' => ['creator' => ['name' => 'someone'], 'created' => 'today']];$name = array_get($array, 'app.creator.name');// someone如果 key 不存在,array_get() 函数还接受可选的第三个参数作为默认值。$name = array_get($array, 'app.created.name', 'anonymous');// anonymouspublic_path()返回 Laravel 应用程序中公共目录的完全限定的绝对路径。 你还可以将路径传递到公共目录中的文件或目录以获取该资源的绝对路径。 它将简单地将 public_path() 添加到你的参数中。$public_path = public_path();$path = public_path('js/app.js');Str::orderedUuid()(1)函数首先生成一个时间戳 uuid。 这个 uuid 可以存储在索引数据库列中。 这些 uuid 是基于时间戳创建的,因此它们会保留你的内容索引;(2)在Laravel 5.6中使用它时,会引发 Ramsey\Uuid\Exception\UnsatisfiedDependencyException。 要解决此问题,只需运行以下命令即可使用 moontoast/math 包composer require laravel/passport=~7.0use Illuminate\Support\Str;return (string) Str::orderByUuid()// A timestamp first uuidstr_plural()将字符串转换为复数形式。该功能只支持英文。echo str_plural('bank');// banksecho str_plural('developer');// developersroute()为指定的路由生成路由 URL。$url = route('login');// 如果路由接受参数,你可以简单地将它们作为第二个参数传递给一个数组。$url = route('products', ['id' => 1]);// 如果你想产生一个相对的 URL 而不是一个绝对的 URL,你可以传递 false 作为第三个参数。$url = route('products', ['id' => 1], false);tap()接受两个参数:一个值和一个闭包。该值将被传递给闭包,然后该值将被返回。闭包返回值无关紧要。$user = App\User::find(1);return tap($user, function($user) { $user->update([ 'name' => 'Random' ]);});/** * 它不会返回布尔值,而是返回 User Model 。如果你没有传递闭包,你也可以使用 User Model 的任何方法。 * 无论实际返回的方法如何,返回值都将始终为值。 在下面的例子中,它将返回 User Model 而不是布尔值。 * update 方法返回布尔值,但由于用了 tap ,所以它将返回 User Model。 */ $user = App\User::find(1);return tap($user)->update([ 'name' => 'SomeName']);dump()会 dump 给定的变量,同时也支持同时传入多个变量。这对调试非常有用。$dump($var1);dump($var1, $var2, $var3);str_slug()将给定的字符串生成一个 URL 友好的 slug。 你可以使用此功能为帖子或产品标题创建一个 slug。$slug = str_slug('Helpers in Laravel', '-');// helpers-in-laraveloptional()接受一个参数,你可以调用参数的方法或访问属性。 如果传递的对象为 null,则方法和属性将返回 null,而不是导致错误或抛出异常。$user = User::find(1);return optional($user)->name;原文地址:https://tutsforweb.com/10-bes...

June 27, 2019 · 1 min · jiezi

laravel-nginx-配置隐藏indexphp

location / { try_files $uri $uri/ /index.php?$query_string;}您可以加上这些,让你的链接更加优雅# 去除末尾的斜杠,SEO更加友好if (!-d $request_filename){ rewrite ^/(.+)/$ /$1 permanent;}# 去除index actionif ($request_uri ~* index/?$){ rewrite ^/(.*)/index/?$ /$1 permanent;}# 根据laravel规则进行url重写if (!-e $request_filename){ rewrite ^/(.*)$ /index.php?/$1 last; break;}error_page 500 502 503 504 /50x.html;location = /50x.html { root html;}

June 27, 2019 · 1 min · jiezi

go语言orm之gorose全新版本20低调发布

号称go语言版本的laravel's eloquent, 发布了久违了2.0版本, 新版本做了很大的改进和升级, 下面我们一起来看一下新版本的特性. 架构调整gorose 2.0版本做了彻底的重构, 拥有全新的架构. 架构如图: gorose 2.0 采用模块化架构, 通过interface的api通信,严格的上层依赖下层.每一个模块都可以拆卸, 甚至可以自定义为自己喜欢的样子. 主模块 engin gorose 初始化配置模块, 可以全局保存并复用session 真正操作数据库底层模块, 所有的操作, 最终都会走到这里来获取或修改数据orm 对象关系映射模块, 所有的orm操作, 都在这里完成builder 构建终极执行的sql模块, 可以构建任何数据库的sql, 但要符合database/sql包的接口子模块 driver 数据库驱动模块, 被engin和builder依赖, 根据驱动来搞事情binder 结果集绑定模块, 所有的返回结果集都在这里其他语言入手姿势php: 使用过laravel的orm就可以快速上手使用python: 使用过orator orm的用户,可以快速上手ruby: 使用过rails的orm就可以快速上手支持驱动mysql : https://github.com/go-sql-dri... sqlite3 : https://github.com/mattn/go-s... postgres : https://github.com/lib/pq oracle : https://github.com/mattn/go-oci8 mssql : https://github.com/denisenkom... clickhouse : https://github.com/kshvakov/c... 特色连接池链式调用支持传入struct,map或字符串表名读写分离集群支持海量数据自动分块处理一键开启事务,自动回滚和提交模块化架构,自由扩展官方文档最新版2.x文档 api预览db.Table().Fields().Where().GroupBy().Having().OrderBy.Limit().Select()db.Table().Data().Insert()db.Table().Data().Where().Update()db.Table().Where().Delete()最佳实践sql DROP TABLE IF EXISTS "users";CREATE TABLE "users" ( "uid" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" TEXT NOT NULL, "age" integer NOT NULL);INSERT INTO "users" VALUES (1, 'gorose', 18);INSERT INTO "users" VALUES (2, 'goroom', 18);INSERT INTO "users" VALUES (3, 'fizzday', 18);实战代码 ...

June 26, 2019 · 2 min · jiezi

Laravel-配置使用七牛云

导语正好有时间,从头配置了一次,下面记录下。 七牛云配置七牛的文档写的很详细,所以只放上官方文档的链接就好了 对象存储,新建存储空间融合 CDN,配置域名在上一步配置域名之后,要到你的域名提供商去绑定,在七牛云文档中也有写安装扩展包以及配置根据文档操作 composer require "overtrue/laravel-filesystem-qiniu"config/app.php 中在 providers 添加 Overtrue\LaravelFilesystem\Qiniu\QiniuStorageServiceProvider::class,config/filesystems.php 中在 disks 添加'qiniu' => [ 'driver' => 'qiniu', 'access_key' => env('QINIU_ACCESS_KEY', 'xxxxxxxxxxxxxxxx'), 'secret_key' => env('QINIU_SECRET_KEY', 'xxxxxxxxxxxxxxxx'), 'bucket' => env('QINIU_BUCKET', 'test'), 'domain' => env('QINIU_DOMAIN', 'xxx.clouddn.com'), // or host: https://xxxx.clouddn.com],然后在 .env 中配置好对应的值。其中 access_key 和 secret_key 在七牛云的个人中心,bucket 是存储空间的名称,domain 是在融合 CDN 中配置的自定义域名 结语使用很简单,参考文档就可以了。因为我用了 laravel-admin,同时修改 config/admin.php 如下 参考资料:七牛云文档中心、laravel-filesystem-qiniu、laravel-admin。

June 22, 2019 · 1 min · jiezi

LeagueCsv导出csv乱码问题

乱码的原因:bom和字符编码不同excel版本要求的字符编码不同,2010以上utf8,2007ansi(可能有错误)除了字符编码还有文件头bom的影响 解决方案:1,用txt打开导出的文件,另存为时选择utf8(如果utf8乱码就选择ansi),在用excel打开另存为的文档;2,在导出的文件的开始地方,如表头处加上bom,如:"xEFxBBxBF".'序号';bom有以下几种; /** * UTF-8 BOM sequence. */const BOM_UTF8 = "\xEF\xBB\xBF";/** * UTF-16 BE BOM sequence. */const BOM_UTF16_BE = "\xFE\xFF";/** * UTF-16 LE BOM sequence. */const BOM_UTF16_LE = "\xFF\xFE";/** * UTF-32 BE BOM sequence. */const BOM_UTF32_BE = "\x00\x00\xFE\xFF";/** * UTF-32 LE BOM sequence. */const BOM_UTF32_LE = "\xFF\xFE\x00\x00";

June 19, 2019 · 1 min · jiezi

一个命令行音乐下载器

music-php 是一个 PHP 写的命令行音乐下载器 安装全局安装$ composer global require guanguans/music-php当前目录安装$ composer create-project guanguans/music-php使用$ ./path/music-php参考链接https://github.com/0xHJK/music-dlhttps://github.com/maicong/musichttps://github.com/metowolf/MetingLicenseMIT

June 19, 2019 · 1 min · jiezi

php中使用protobuffer

Protobuf 简介protobuf(Protocol buffers)是谷歌出品的跨平台、跨语言、可扩展的数据传输及存储的协议,是高效的数据压缩编码方式之一。 Protocol buffers 在序列化数据方面,它是灵活的,高效的。相比于 XML 来说,Protocol buffers 更加小巧,更加快速,更加简单。一旦定义了要处理的数据的数据结构之后,就可以利用 Protocol buffers 的代码生成工具生成相关的代码。甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。 Protocol buffers 很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。 此外,Protobuf由于其在内网高效的数据交换效率,是被广泛应用于微服务的,在谷歌的开源框架grpc即是基于此构建起来的。 php-protobuf安装由于protobuf原生并不支持php,所以php如果使用pb则需要安装相应扩展。 pecl install protobuf环境中需要有protoc编译器,下载安装方式: $ wget https://github.com/google/protobuf/releases/download/v2.5.0/protobuf-2.5.0.tar.gz$ tar zxvf protobuf-2.5.0.tar.gz$ cd protobuf-2.5.0$ ./configure --prefix=/usr/local/protobuf$ sudo make $ sudo make install验证安装成功: $ /usr/local/protobuf/bin/protoc --versionlibprotoc 2.5.0php-protobuf安装成功 php --ri protobuf安装lumen和google/protobuf依赖lumen new rpclumen new rpc命令相当于composer create-project laravel/lumen rpccomposer require google/protobuf在composer.json下添加classmap: { "classmap": [ "protobuf/" ]}ok,准备工作都已做好了。 自己做一个demo在代码目录下创建一个protobuf文件夹mkdir protobuf 进入该目录,创建一个文件searchRequest.proto syntax = "proto3";message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4;}????此处很重要????在composer.json下添加classmap,否则将无法侦测到对应class{ "classmap": [ "protobuf/" ]}在命令行下运行:protoc --proto_path=protobuf/ --php_out=protobuf/ protobuf/searchRequest.proto && composer dump-autoload ...

June 18, 2019 · 2 min · jiezi

Tidewaysxhprof-和-xhgui-打造-PHP-非侵入式监控平台

推荐阅读Tideways、xhprof 和 xhgui 打造 PHP 非侵入式监控平台超全的设计模式简介(45种)design-patterns-for-humans 中文版MongoDB 资源、库、工具、应用程序精选列表中文版有哪些鲜为人知,但是很有意思的网站?一份攻城狮笔记每天搜集 Github 上优秀的项目一些有趣的民间故事超好用的谷歌浏览器、Sublime Text、Phpstorm、油猴插件合集环境准备安装之前确保已经正确安装了以下软件 PHPNginxMongodb安装 PHP mongodb 扩展$ sudo pecl install mongodbPHP 配置文件中添加 [mongodb]extension=mongodb.so安装 PHP tideaways 扩展常规编译安装 $ git clone https://github.com/tideways/php-xhprof-extension.git$ cd /path/php-xhprof-extension$ phpize$ ./configure$ make$ sudo make installPHP 配置文件中添加 [tideways]extension=tideways_xhprof.so; 不需要自动加载,在程序中控制就行tideways.auto_prepend_library=0; 频率设置为100,在程序调用时可以修改tideways.sample_rate=100安装 xhgui-branch(xhgui 的汉化版)$ git clone https://github.com/laynefyc/xhgui-branch.git$ cd xhgui-branch$ php install.php修改 xhgui-branch 配置文件 <?phpreturn array( ... 'extension' => 'tideways_xhprof', ... 'save.handler' => 'mongodb', 'db.host' => 'mongodb://127.0.0.1:27017', 'db.db' => 'xhprof', ...);启动 mongodb 并设置 xhgui 索引,命令如下:$ mongo> use xhprof> db.results.ensureIndex( { 'meta.SERVER.REQUEST_TIME' : -1 } )> db.results.ensureIndex( { 'profile.main().wt' : -1 } )> db.results.ensureIndex( { 'profile.main().mu' : -1 } )> db.results.ensureIndex( { 'profile.main().cpu' : -1 } )> db.results.ensureIndex( { 'meta.url' : 1 } )xhgui 本地虚拟主机配置参考server { listen 80; server_name xhgui.test; root /Users/yaozm/Documents/wwwroot/xhgui-branch/webroot; # access_log /usr/local/var/log/nginx/access.log; error_log /usr/local/var/log/nginx/error.log; location / { try_files $uri $uri/ /index.php?$query_string; index index.php index.html index.htm; }}针对要分析的站点进行设置,直接在要分析站点的 nginx 配置中增加以下项,然后使配置生效就可以了。$ fastcgi_param PHP_VALUE "auto_prepend_file=/path/xhgui-branch/external/header.php";参考配置 ...

June 18, 2019 · 1 min · jiezi

Windows-环境下安装-OpenSSL证书

第一步:下载 OpenSSL Windows 编译版 安装 OpenSSL 有两种方式。第一种直接下载编译版 OpenSSL ; 第二种自己下载源码自己编译。本文仅对第一种方法进行描述。首先进入: http://slproweb.com/products/... → 根据自己系统位数选择相应版本。也可以在本站进行下载。[合信ssl证书]https://ssl.51mubanji.com/ 第二步:安装 OpenSSL Windows 编译版 点击: NextOpenSSL 安装步骤选择: I accept the agreement点击: NextOpenSSL 安装步骤点击: NextOpenSSL 安装步骤点击: NextOpenSSL 安装步骤点击: NextOpenSSL 安装步骤点击: InstallOpenSSL 安装步骤点击: FinshOpenSSL 安装步骤第三步:设置 OpenSSL 系统变量 进入: 控制面板 → 系统和安全 → 系统点击: 高级系统设置OpenSSL 安装步骤点击: 环境变量OpenSSL 安装步骤选择: Path点击: 编辑OpenSSL 安装步骤点击: 新建OpenSSL 安装步骤输入: C:OpenSSL-Win64bin点击: 确定OpenSSL 安装步骤点击: 确定OpenSSL 安装步骤点击: 确定OpenSSL 安装步骤第四步:测试 OpenSSL 运行环境 打开命令提示符,输入: opensslOpenSSL 安装步骤如果出现以下信息则代表我们设置成功OpenSSL 安装步骤 ...

June 17, 2019 · 1 min · jiezi

Laravel-使用-RabbitMQ

导语RabbitMQ 想必大家都有了解,不做多介绍来。这里实现的是用 RabbitMQ 作为 Larvel 队列的驱动,替代 Redis。下面以 Laradock 中安装示例。 安装切换到 laradock 目录,将 .env 中关于 INSTALL_AMQP 的值修改为 truedocker-compose stop workspace php-fpm php-workerdocker-compose build workspace php-fpm php-worker rabbitmqdocker-compose up -d workspace php-fpm php-worker rabbitmq扩展包安装以及配置进入到 workspace 容器中,在项目目录安装扩展包 composer require vladimir-yuldashev/laravel-queue-rabbitmq接下来在 config/queue.php 文件中 connections 添加 rabbitmq 配置,根据情况自行修改'rabbitmq' => [ 'driver' => 'rabbitmq', /* * Set to "horizon" if you wish to use Laravel Horizon. */ 'worker' => env('RABBITMQ_WORKER', 'default'), 'dsn' => env('RABBITMQ_DSN', null), /* * Could be one a class that implements \Interop\Amqp\AmqpConnectionFactory for example: * - \EnqueueAmqpExt\AmqpConnectionFactory if you install enqueue/amqp-ext * - \EnqueueAmqpLib\AmqpConnectionFactory if you install enqueue/amqp-lib * - \EnqueueAmqpBunny\AmqpConnectionFactory if you install enqueue/amqp-bunny */ 'factory_class' => Enqueue\AmqpLib\AmqpConnectionFactory::class, 'host' => env('RABBITMQ_HOST', '127.0.0.1'), 'port' => env('RABBITMQ_PORT', 5672), 'vhost' => env('RABBITMQ_VHOST', '/'), 'login' => env('RABBITMQ_LOGIN', 'guest'), 'password' => env('RABBITMQ_PASSWORD', 'guest'), 'queue' => env('RABBITMQ_QUEUE', 'default'), 'options' => [ 'exchange' => [ 'name' => env('RABBITMQ_EXCHANGE_NAME'), /* * Determine if exchange should be created if it does not exist. */ 'declare' => env('RABBITMQ_EXCHANGE_DECLARE', true), /* * Read more about possible values at https://www.rabbitmq.com/tutorials/amqp-concepts.html */ 'type' => env('RABBITMQ_EXCHANGE_TYPE', \Interop\Amqp\AmqpTopic::TYPE_DIRECT), 'passive' => env('RABBITMQ_EXCHANGE_PASSIVE', false), 'durable' => env('RABBITMQ_EXCHANGE_DURABLE', true), 'auto_delete' => env('RABBITMQ_EXCHANGE_AUTODELETE', false), 'arguments' => env('RABBITMQ_EXCHANGE_ARGUMENTS'), ], 'queue' => [ /* * Determine if queue should be created if it does not exist. */ 'declare' => env('RABBITMQ_QUEUE_DECLARE', true), /* * Determine if queue should be binded to the exchange created. */ 'bind' => env('RABBITMQ_QUEUE_DECLARE_BIND', true), /* * Read more about possible values at https://www.rabbitmq.com/tutorials/amqp-concepts.html */ 'passive' => env('RABBITMQ_QUEUE_PASSIVE', false), 'durable' => env('RABBITMQ_QUEUE_DURABLE', true), 'exclusive' => env('RABBITMQ_QUEUE_EXCLUSIVE', false), 'auto_delete' => env('RABBITMQ_QUEUE_AUTODELETE', false), 'arguments' => env('RABBITMQ_QUEUE_ARGUMENTS'), ], ], /* * Determine the number of seconds to sleep if there's an error communicating with rabbitmq * If set to false, it'll throw an exception rather than doing the sleep for X seconds. */ 'sleep_on_error' => env('RABBITMQ_ERROR_SLEEP', 5), /* * Optional SSL params if an SSL connection is used * Using an SSL connection will also require to configure your RabbitMQ to enable SSL. More details can be founds here: https://www.rabbitmq.com/ssl.html */ 'ssl_params' => [ 'ssl_on' => env('RABBITMQ_SSL', false), 'cafile' => env('RABBITMQ_SSL_CAFILE', null), 'local_cert' => env('RABBITMQ_SSL_LOCALCERT', null), 'local_key' => env('RABBITMQ_SSL_LOCALKEY', null), 'verify_peer' => env('RABBITMQ_SSL_VERIFY_PEER', true), 'passphrase' => env('RABBITMQ_SSL_PASSPHRASE', null), ],],在 .env 中修改 QUEUE_CONNECTION 为 rabbitmq,并添加以下值RABBITMQ_WORKER=horizonRABBITMQ_HOST=rabbitmqRABBITMQ_PORT=5672RABBITMQ_LOGIN=guestRABBITMQ_PASSWORD=guestRABBITMQ_QUEUE=default有两个值说明一下,因为是在 Laradock 中,所以 RABBITMQ_HOST 设置为 rabbitmq;如果之前使用了Laravel Horizon,那么 RABBITMQ_WORKER 的设置为 horizon 就可以了。 ...

June 17, 2019 · 2 min · jiezi

Laravel-Horizon-配置以及使用

导语Horizon 为 Laravel 提供了基于 Redis 的、拥有美观后台的、代码驱动配置的队列系统。Horizon 让我们可以轻松监控队列系统的关键指标,例如任务吞吐量、运行时间和失败任务等。Laravel Horizon 是官方的扩展包,配置以及使用很简单,跟着文档就可以。 安装以及配置composer require laravel/horizon安装好之后,发布资源 php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"配置文件在 config/horizon.php,可以根据需求修改使用运行 php artisan horizon访问 you_site.com/horizon 就可以看到后台了还有其他命令 暂停 php artisan horizon:pause继续 php artisan horizon:continue执行完所有任务后退出 php artisan horizon:terminate部署可以看到使用很简单,在部署的时候要注意以下几点 确保有 failed_jobs 数据表,相关文档可以看这里默认情况下,只能在 local 访问,当然我们可以自定义 首先修改 config/horizon.php 中 environments 配置项。可以看到其中有 local 和 production,将 production 修改为线上 .env 中 APP_ENV 的值接下来可以自定义后台的访问策略,使用 Horizon:auth 方法,return true 即可访问,否则返回 403。在 app/Providers/AppServiceProvider.php 中修改如下public function boot(){ Horizon::auth(function ($request) { // 这里进行判断,根据需求自行选择 // 通过认证可以访问 if (Auth::check()) { return true; } // 指定参数可以访问 if ($request->input('q') == 'horizon') { return true; } });}使用 Supervisor 进程守护,配置如下,根据情况进行修改(可以参考这两篇文章,这里,那里)[program:horizon]process_name=%(program_name)scommand=php /var/www/you_project_path/artisan horizonautostart=trueautorestart=trueuser=laradockredirect_stderr=truestdout_logfile=/var/www/you_project_path/horizon.log使用调度任务来生成监控,以便查看运行情况,在 app/Console/Kernel.php 修改如下protected function schedule(Schedule $schedule){ // $schedule->command('inspire') // ->hourly(); $schedule->command('horizon:snapshot')->everyFiveMinutes();}结语Laravel Horizon 还有标签以及通知的配置,感兴趣的可以查看文档。 ...

June 16, 2019 · 1 min · jiezi

laravel前后端分离获取微信授权结合laravelwechat

1、开始之前,请一定仔细阅读微信开发者文档文档中,总共写了几个步骤: 1、通过appId和需要跳转的路由去请求授权2、授权之后跳转路由中返回的code 注:前端只需要知道这两个步骤3、根据code获取access_token4、根据access_token获取用户信息(snsapi_userinfo授权)2、前端发起授权请求。这一步需要前端拼凑路由,并且将页面跳转到拼凑路由,路由规则如:https://open.weixin.qq.com/connect/oauth2/authorize?appid=你的公众appId号&redirect_uri=你的回调路由&response_type=code&scope=你选择的方式&state=STATE#wechat_redirect注 授权方式可选择为snsapi_userinfo或者snsapi_base,差别请看文档跳转之后授权页面如下(开发者工具效果) 3、点击同意之后,会根据你之前拼凑的回调路由返回code,如下:http://test.***.com/index?code=021Azdiu12zdXd05kkju1ZYkiu1AzdiR&state=1 4、将路由中的code直接传递给后端,让后端做获取用户信息的系列的逻辑处理。注:如下是laravel中间件中处理方式,session只用于这次请求,也可以将用户的微信信息放在request中到controller进行逻辑处理,看个人喜好 public function handle($request, Closure $next, $scopes = null) { $wechatCacheKey = 'wechat.oauth_user.default'; if (config("qa.mock_user") == 1){ $user = new SocialiteUser(config('wechat.mock_user')); } else { $code = $request->get("code", ""); if ($code === ""){ $appId = $this->config["app_id"]; return Response::toJson(["aid" => $appId], "请重新获取授权CODE!",10006); } // 开始拉取用户信息 $app = Factory::officialAccount($this->config); $user = $app->oauth->user(); } session([$wechatCacheKey => $user]); } return $next($request); }注:这个例子只是写了授权的逻辑,token相关验证我已经做了剔除 坑点:1、vue的路由会将code拼接在url和#之间,如www.****.com/?code=XXXXX/#/index,这个code需要单独处理

June 14, 2019 · 1 min · jiezi

Laravel-基于-Scout-配置实现-Elasticsearch-二-配置以及使用

导语上篇文章搭建了 Elasticsearch 容器以及添加了测试数据,这篇来配置以及使用。 安装扩展包以及配置composer require tamayo/laravel-scout-elastic在 config/app.php 中 providers 添加 Laravel\Scout\ScoutServiceProvider::class 和 ScoutEngines\Elasticsearch\ElasticsearchProvider::class,发布配置文件 php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"在 config/scout.php 添加'elasticsearch' => [ 'index' => env('ELASTICSEARCH_INDEX', 'laravel'), 'hosts' => [ env('ELASTICSEARCH_HOST', 'http://localhost'), ],],编辑 .env 文件,所以添加如下配置项SCOUT_DRIVER=elasticsearchELASTICSEARCH_INDEX=laravel_indexELASTICSEARCH_HOST=elasticsearch #因为环境是 laradock修改模型配置修改 app/Models/FakeArticle.php 文件如下 <?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Laravel\Scout\Searchable;class FakeArticle extends Model{ Use Searchable; /** * 需要查询的字段 * @return array */ public function toSearchableArray() { return $this->only('author', 'title', 'content'); }}设置 Elasticsearch 分词策略这一步是花费时间最多的地方,查的资料要么是过时的,要么根本不能运行。最终根据这篇文章修改而来。关于 ik 分词以及 ik_max_word 和 ik_smart 的区别,不在这里赘述了,可以看下这篇文章。 ...

June 13, 2019 · 2 min · jiezi

Laravel-基于-Scout-配置实现-Elasticsearch-一-准备工作

导语全文搜索是很重要的功能,实现的方式也有很多种。以下通过 Laravel Scout 和 Elasticsearch 实现。先来看下各自的介绍 Laravel Scout 为 Eloquent 模型全文搜索实现提供了简单的、基于驱动的解决方案。通过使用模型观察者,Scout 会自动同步更新模型记录的索引。Elasticsearch是一个基于Lucene库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎,具有HTTP Web接口和无模式JSON文档。Elasticsearch是用Java开发的,并在Apache许可证下作为开源软件发布。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。[5]根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。新建测试数据新建 fake_articles 用来测试 新建模型以及数据迁移 php artisan make:model Models/FakeArticle -m在数据迁移中 database/migrations/2019_06_13_095420_create_fake_articles_table.php 编辑如下public function up(){ Schema::create('fake_articles', function (Blueprint $table) { $table->increments('id'); $table->string('author', 20)->comment('作者'); $table->string('title', 200)->comment('标题'); $table->text('content')->comment('内容'); $table->timestamps(); });}生成数据表 php artisan migrate新建数据填充 php artisan make:seeder FakeArticlesSeeder填充几条中文数据,以便后续测试public function run(){ \App\Models\FakeArticle::insert([ [ 'author' => '王二', 'title' => '黄金时代', 'content' => '那一天我二十一岁,在我一生的黄金时代,我有好多奢望。我想爱,想吃,还想在一瞬间变成天上半明半暗的云,后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消逝,最后变得像挨了锤的牛一样。可是我过二十一岁生日时没有预见到这一点。我觉得自己会永远生猛下去,什么也锤不了我。', 'created_at' => now(), 'updated_at' => now(), ], ['author' => '陈辉', 'title' => '绿毛水怪', 'content' => '大团的蒲公英浮在街道的河流口,吞吐着柔软的针一样的光,我们好像在池塘的水底,从一个月亮走向另一个月亮。', 'created_at' => now(), 'updated_at' => now(), ], ['author' => '迅哥', 'title' => '社戏', 'content' => '两岸的豆麦和河底的水草所发散出来的清香,夹杂在水气中扑面的吹来;月色便朦胧在这水气里。淡黑的起伏的连山,仿佛是踊跃的铁的兽脊似的,都远远的向船尾跑去了,但我却还以为船慢。他们换了四回手,渐望见依稀的赵庄,而且似乎听到歌吹了,还有几点火,料想便是戏台,但或者也许是渔火。', 'created_at' => now(), 'updated_at' => now(), ] ]);}运行填充 php artisan db:seed --class=FakeArticlesSeeder搭建 Elasticsearch 容器laradock 中支持 Elasticsearch,直接搭建就可以,省去了诸多麻烦 ...

June 13, 2019 · 1 min · jiezi

配置-Supervisor自动重启常驻进程

问题:PHP 常驻进程经常出现死掉的情况;解决方案:使用 Supervisor, 当进程死掉时,可以重启,不局限于PHP进程,任何进程,都可以用Supervisor 进行重启。 1、安装 安装python应该就可以了,python 安装包自带 Supervisor或者用pip安装Supervisor进程管理工具参考链接:https://www.cnblogs.com/Dicky-Zhang/p/6171954.html2、配置 2.1 生成配置文件在Mac下,由于安全规则,默认不能在/etc/下增加配置,不过可以在/usr/local/etc目录下创建配置文档,效果是一样的。sudo echo_supervisord_conf > /usr/local/etc/supervisord.conf可以使用上述命令,生成配置文件。其中,echo_supervisord_conf命令可以打印所有的默认配置信息;2.2 配置后台管理页面,解开下面的注释就可以了[inet_http_server]port=127.0.0.1:9001 username=userpassword=1232.3 配置进程重新启动时的命令,在配置文件中,新增下面几行代码[program:apple]process_name=%(program_name)s_%(process_num)02dcommand=php artisan appleautostart=trueautorestart=true;user=usernumprocs=8redirect_stderr=truestdout_logfile=/var/log/supervisor.log3、启动supervisor的守护进程 sudo supervisord -c /usr/local/etc/supervisord.conf其中,需要用 -c 参数指定配置文件。4、管理常驻进程 supervisor守护启动成功后,要自动重启的命令就已经正常运行了。通过本地浏览器,进入管理后台:http://127.0.0.1:9001/,打开效果图如下可以在后台看到进程的相关信息,如运行了多长时间也可以,做相关操作,如停止进程、重启进程、查看log、清除log

June 12, 2019 · 1 min · jiezi

laradock-中安装-Laravel-Dusk

导语在本地安装 Laravel Dusk 一直失败,查了文档才发现在 laradock 中并不是只需要 composer require 就可以的,还有其他配置。下面记录一下。 配置 laradock切换到 laradock 目录中,将 workspace 容器先暂停 docker-compose sotp workspace修改 .env 文件中的 WORKSPACE_INSTALL_LARAVEL_INSTALLER 和 WORKSPACE_INSTALL_DUSK_DEPS,将配置值改为 true重新搭建 workspace 容器 docker-compose build workspace成功之后启动 docker-compose up -d workspace安装 Laravel Dusk进入到 workspace 容器中 docker-compose exec workspace bash,并且切换到项目目录中使用 composer require --dev laravel/dusk 安装 Laravel Dusk执行 php artisan dusk:install在 tests/DuskTestCase.php 文件中,修改 driver 方法,添加 —-no-sandbox 参数,如下protected function driver(){ $options = (new ChromeOptions)->addArguments([ '—disable-gpu', '—headless', '—window-size=1920,1080', '—no-sandbox',// 添加这行 ]); return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome()->setCapability( ChromeOptions::CAPABILITY, $options ) );}添加一个配置文件,cp .env .env.dusk.local,将 APP_URL 修改为 http://localhost:8000执行 php artisan serve —-quiet &最后可以使用 Laravel Dusk 进行测试了 php artisan dusk结语其实在 workspace 中有很多 alias 可是使用,为了便于理解,都是用了原命令。关于 Laravel Dusk 的使用,可以参考这个教程,其中不止关于测试的部分,其他部分很好。 ...

June 12, 2019 · 1 min · jiezi

Laravel中的Auth

Laravel中的Authlaravel中有一个组件叫auth,auth组件提供了整个框架的认证功能,这里想简单追踪一下它的实现逻辑。 首先从 php artisan make:auth 开始# Illuminate\Auth\Console\AuthMakeCommand.phppublic function handle(){ // 创建存放auth前端界面的目录和文件 // 模版存放在Auth\Console的stubs下 $this->createDirectories(); $this->exportViews(); if (! $this->option('views')) { // 生成HomeController控制器文件 file_put_contents( app_path('Http/Controllers/HomeController.php'), $this->compileControllerStub() ); // 生成auth相关路由 file_put_contents( base_path('routes/web.php'), file_get_contents(__DIR__.'/stubs/make/routes.stub'), FILE_APPEND ); }}生成文件resources/views/auth、 resources/layouts路由文件 web.php 、和 Http/Controllers/Auth 下的控制器 说一说csrf-token<!-- CSRF Token --><meta name="csrf-token" content="{{ csrf_token() }}"> function csrf_token() { $session = app('session'); if (isset($session)) { return $session->token(); } throw new RuntimeException('Application session store not set.'); } LoginController的login方法 public function login(Request $request) { // 检查请求体 $this->validateLogin($request); // 判断是否请求失败太多次 if ($this->hasTooManyLoginAttempts($request)) { $this->fireLockoutEvent($request); return $this->sendLockoutResponse($request); } // 判断是否验证通过 if ($this->attemptLogin($request)) { return $this->sendLoginResponse($request); } // 记录请求失败次数 $this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request); } ...

June 11, 2019 · 2 min · jiezi

开源-LaravelPlus-基于-Laravel-魔改为方便实际业务使用-开发中

目的为了减少重复 CURD 和新项目的配置麻烦等问题,(就是为了骗星星:LaravelPlus )如: 现有的 infyomlabs/laravel-generator CODE 生成工具虽然好用,但是不太喜欢样式和代码结构。有些本地,测试,线上的配置需要频繁改动的需要。多个项目构建引入包,配置扩展等重复性操作介绍LaravelPlus 基于 Laravel 增加部分软件包初始安装和进行业务使用功能改动,来创建一个开箱即用的应用 版本基础当前版本基于 PHPLaravel(影响不大,降低版本理论可以)>=7.1.3>=5.8项目使用说明下载项目// 1. github (推荐)$ git clone https://github.com/ElapseAnnals/LaravelPlus.git $ git checkout v5.8.0 // 切换至当前最新稳定版本// 或// 2. composer$ composer create-project elapse-annals/laravel-plus$ mv laravel-plus LaravelPlus#### 复制项目 // 1.在当前目录运行自动复制脚本 (推荐)$ php LaravelPlus/create YourProject// 或 // 2.在当前目录手动复制项目至自身项目$ cd LaravelPlus$ rm composer.lock$ rsync -av --exclude . --exclude .. --exclude .git/ --exclude vendor/ --exclude .github/ LaravelPlus/* YourProject // 为消除对称 */ $ cd YourProject$ rm composer.lock .env .travis$ cp .env.example .env 初始化$ cd YourProject // 进入 YourProject 项目中$ composer install // 更新软件包 (请先已安装 composer )$ php artisan key:generate // 更新 key$ php artisan vendor:publish // 发布扩展包的资源$ php artisan migrate // 迁移$ php artisan storage:link // 图片资源软连接映射【非必须】Tips: ...

June 9, 2019 · 2 min · jiezi

一个用于收藏文章的扩展包-Laravel-Collect

Laravel Collect 是我开发的一个收藏文章的扩展,借鉴于 cybercog/laravel-love ,我也有幸参加了社区对该扩展的外文翻译文章 为你的 Eloquent 模型添加喜欢和讨厌功能。我的初衷是学习怎么开发 Laravel 扩展包,所以实现的功能可能比较简单,请大神勿喷。但是对于想学习开发 Laravel 扩展包的同学还是不错的。望大家点赞支持,感谢。 最近发现已经有人使用我的扩展包到项目里,我更有动力不断更新完善。fight! 安装通过 composer 安装,命令如下: $ composer require vetor/laravel-collect我们需要执行模型迁移命令,将 Collections 表发布到我们的数据库: $ php artisan migrate使用在我们的收藏者表,即 User 表里需要实现 CollectorContract 接口,并引用 Collector trait: use Illuminate\Foundation\Auth\User as Authenticatable;use Vetor\Laravel\Collect\Collector\Models\Traits\Collector;use Vetor\Contracts\Collect\Collector\Models\Collector as CollectorContract;class User extends Authenticatable implements CollectorContract{ use Collector;}如果用户需要收藏文章,在 Article 表里实现 CollectableContract 接口并引用 Collectable trait 即可: use Vetor\Laravel\Collect\Collectable\Models\Traits\Collectable;use Vetor\Contracts\Collect\Collectable\Models\Collectable as CollectableContract;class Article extends Model implements CollectableContract{ use Collectable;}可用的方法对于用户来说,可用的方法有: ...

June 7, 2019 · 1 min · jiezi

在Repository模式下使用laravel

laravel-repository仓库地址Github Repository文档地址 清晰的目录结构Models只负责定义模型(如:模型关联,scope,get和set attribute等)Repository负责处理这个表相关的所有业务逻辑, 不只是注入model, 相关的redis任何cache都可以注入,代码定位迅速Controllers 只负责处理简单的逻辑,获取转发数据,它应该是 简洁干净 的AppHttpControllerAdmin IndexControllerUserControllerConfigController...Request(所有的request验证类)Admin Index StoreRequestUpdateRequestDestroyRequestUser ...Config ...Request.phpModels (所有的model模型)User(用户相关的所有模型)User.phpUserExt.phpUserMessage.phpConfigConfig.php...BaseModel.phpRepositories (目录结构应与model一致,结构清晰)User(用户相关的所有仓库)UserRepository.phpUserExtRepository.phpUserMessageRepository.php...安装并使用composer require littlebug/laravel-repositorymkdir app/Http/Requests# 创建属于你自己的Request验证基类# 就像下面这个文件关于一键生成代码# 在将命令注入到你的laravel 项目以后# 输入php artisan list# 如果你看到下面这些提示,那么可以开始快速生成代码了!~ core core:controller 生成 Controller {--table=} 指定表名称 [ 指定该参数会通过表生成视图文件 ] {--name=} 指定名称 可以带命名空间 [ --name=Home/IndexController 或者 Home\\IndexController ] {--r=} 指定 Repository 需要从 Repositories 目录开始; 默认使用控制器同名 Repository {--request=} 指定 request 目录; 需要从 Requests 目录开始; 默认使用控制器命名空间 {--pk=} 指定主键名称,默认id core:generate 生成 controller|model|repository|request|views {--table=} 指定表名称 [ 支持指定数据库,例如:log.crontabs ] {--path=} 指定目录 [ 没有传递绝对路径,否则使用相对对路径 从 app/Models 开始 ] {--model=} model名称 默认生成使用表名称生成 core:model # 让我们来试一下# 在commands帮助文档的提示下生成代码# 如果你的项目用到了数据库前缀,不要忘了去database.php中添加,否则会找不到table# 举个栗子,以member_message表为例php artisan core:generate --table=member_message --path=Member --controller=Member/MemberMessageController# 在终端中你可以看到下面的结果文件 [ /Users/wanchao/www/lara-test/app/Models/Member/MemberMessage.php ] 生成成功文件 [ /Users/wanchao/www/lara-test/app/Repositories/Member/MemberMessageRepository.php ] 生成成功文件 [ /Users/wanchao/www/lara-test/app/Http/Requests/Member/MemberMessage/UpdateRequest.php ] 生成成功文件 [ /Users/wanchao/www/lara-test/app/Http/Requests/Member/MemberMessage/DestroyRequest.php ] 生成成功文件 [ /Users/wanchao/www/lara-test/app/Http/Requests/Member/MemberMessage/StoreRequest.php ] 生成成功# 添加路由 routes/web.phpRoute::group(['namespace' => 'Member','prefix' => 'member'], function ($route) { $route->get('index', 'MemberController@indexAction'); $route->get('message', 'MemberMessageController@indexAction');});### 修改MemberMessageController### 在MemberMessageController中dd打印数据public function index(){ $filters = Helper::filter_array(request()->all()); $filters['order'] = 'id desc'; $list = $this->memberMessageRepository->paginate($filters); dd($list);}# 终端php artisan servevist localhost:8001/member/message# 你应该尝试一些你的数据库中存在的表,而不是机械的去复制粘贴我的栗子 ...

June 5, 2019 · 1 min · jiezi

Laravel-58集合-vueelementadmin-踩坑记

创建 Laravel 项目按照官方文档,进行安装: composer create-project --prefer-dist laravel/laravel laravel-vue-admin 下载 vue-element-admin$ git clone https://github.com/PanJiaChen/vue-element-admin.git初始化package将 vue-element-admin 中 package.json 中的 dependencies 与devDependencies 合并到 Laravel 的 package.json 中。 版本以 vue-element-admin 的版本为准 复制文件将 vue-element-admin 中整个 src 目录下的文件复制到 laravel 项目中的 resources/backend 目录中。 安装前端依赖$ npm install 添加打包语句修改 webpack.mix.js 为: const mix = require('laravel-mix');mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css');mix.js('resources/backend/main.js', 'public/js')添加入口文件在 resources/views 中添加 admin.blade.php 视图文件,代码如下: <!doctype html><html lang="{{ app()->getLocale() }}"><head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>title</title></head><body><div id="app"></div><script src="{{ mix('/js/main.js') }}"></script></body></html>配置路由映射在 routes/web.php 文件中添加如下路由: ...

June 5, 2019 · 3 min · jiezi

laraveladmin-与-vue-结合使用

laravel-admin 与 vue 结合使用由于 Laravel-admin 采用的是 pjax 的方式刷新页面,意味着很多页面刷新的操作,并不是刷新整个 document,而是从服务器拿到部分 document,再通过类似 $(“#pjax-container”).html(newPart) 的方式更新的。 这就造成一个问题,每次 pjax 刷新,都会破坏 vue 的 dom 映射。 所以理论上有2种方法解决: 重新绑定一下 vue 的映射关系在某些页面禁止 pjax1 太难搞,而且没啥资料,放弃。2 的话比较可行。 部分禁止 pjax打开 public/vendor/laravel-admin/laravel-admin/laravel-admin.js添加代码: // 不使用 pjax 刷新的页面$(document).on('pjax:beforeReplace', function (e, options) { // console.log(arguments) var freshPaths = [ /\/admin.*\/products/, ] for (let path of freshPaths) { if (path.test) { if (path.test(e.state.url)) { location.reload() return false } } else if (options.url.search(path) !== -1) { location.reload() return false } }})使用自定义 view很多时候我们并不需要大动干戈地建立一个全部的 view,只需要在内置 view 中稍作修改。这时候,我们需要先自定义一个 Content 类: ...

June 4, 2019 · 2 min · jiezi

laravel常见问题

Laravel - 500内部服务器错误确定文件夹 storage 是否有权限 软件版本 php 7.1.29Apache 2.4.39Mysql 5.7.26wamp 3.1.9 错误日志位置storagelogs Laravel 出现 No application encryption key has been specified.若文件根目录下没有 .env1、.env.example 改名使用命令 copy 修改为 .env2、使用命令 php artisan key:generate 获取密码,自动保存到 .env3、将密码复制到config/app.php 中的key里面4、重新运行,OK。

June 4, 2019 · 1 min · jiezi

12Laravel全文搜索Elasticsearch-三

使用Elasticsearch搜索引擎,配置ik中文分词,与Laravel模型关联,然后实现搜索的业务逻辑。本篇是结束篇,使用Laravel的Scout扩展包完成搜索功能续上篇,已经安装和配置好了Scout和支持Elastic的扩展包 编辑Article模型,将LaravelScoutSearchable 这个 trait加到你想要做检索的模型,这个trait会注册一个模型观察者来保持模型同步到检索服务的驱动: <?phpnamespace App;use Illuminate\Database\Eloquent\Model;use Laravel\Scout\Searchable;class Article extends Model{ // 引入这个trait,这个trait会注册一个模型观察者来保持模型同步到检索服务的驱动 use Searchable;//... // 定义索引里面的type(类型)-- es中类型相当于mysql中的表 public function searchableAs() { return 'article'; } // 定义有哪些字段需要搜索 public function toSearchableArray() { return [ 'id' => $this->id, 'title' => $this->title, 'content' => $this->content ]; }//...}使用aritsan命令,从mysql导入现有数据到ElasticSearch php artisan scout:import查看一下ElasticSearch中是否存在配置的索引,和导入的数据大小 curl 'localhost:9200/_cat/indices?v'ElasticSearch的一些RESTful api调用方式,可以用来测试数据 查看索引的配置 curl -XGET "http://localhost:9200/mi360?pretty=true"查看文档列表 curl -XGET "http://localhost:9200/mi360/_search?pretty=true"查看指定id=10的文档 curl -XGET "http://localhost:9200/mi360/article/10?pretty=true"ok!导入成功后,开始写搜索业务逻辑了 添加路由 Route::get('/search', 'WelcomeController@search');编辑视图文件中的form表单,提交到路由的地址,并且input表单的name=query <form action="{{ url('/search') }}" class="search fr"> <input type="text" name="query" placeholder="客官,想搜点啥?"> <button type="submit">搜索</button></form>编写控制器 ...

May 29, 2019 · 2 min · jiezi

Web-API-开发实践

前言demo代码链接:github代码 基本架构代码分层应用的基本架构主要包含以下5个部分: Controller Layer(控制器层)Transformer Layer(转换层)Service Layer(服务层)Repository Layer(仓库层)Model Layer(模型层)各个层次的主要职责如下图所示 详细说明 基本的程序流程如上图所示,从1到8。若业务逻辑比较简单,可以直接跳过Service层,由Controller层直接调用Repository层。各层次之间可以通过依赖注入联系起来。业务逻辑主要分布在Service层和Model层。Service层负责工作流逻辑,即任务的具体执行流程,如事务处理等;Model层负责领域逻辑,领域逻辑包括了业务规则、业务计算等。通常情况下,Service层由于包含了主要的工作流逻辑,其可复用性比较差,但当Service层的业务逻辑积累到一定程度的时候,会沉淀一些通用的业务逻辑(工作流逻辑),最好将通用的业务逻辑提取出来,形成一个Service层内的子层,称为“通用处理层”(General Process Layer),可以将这部分代码放到当前Services目录下的General目录中。Service层的返回值: 1.业务对象(model等业务数据)2.bool值,指示处理结果。当Service层的业务逻辑无法正常执行时,需要抛出业务处理异常BusinessException(注意,不是程序执行异常。业务处理异常例子:如账户余额不足,无法转账)。通过业务处理异常,将不正常的业务处理结果返回给调用者(eg:Controller或其他Service)。而在正常执行业务逻辑的情况下,则返回Service层的正常返回值,即上面第5点。在每一层中,当新开一个子分类时,最好建立一个子分类的基类。以Controller层为例子,当需要在app/Api/Controllers/V1目录建立一个Insurance子目录时,最好在建好后的目录中添加一个BaseController,作为该目录下的基类。Model层可以细分为AR(ActiveRecord)层和Domain层。Domain层通常是基于AR层。AR层中每个类对应一张数据库表,而Domain类中包含的数据可以来自多个AR类。 通常会在AR层中写与数据库相关的代码,如表的关联关系,表属性的可取值等。通常会在Domain层中写相应的领域逻辑。eg : 领域模型某些值的取值规则Domain类代表一个完整的领域模型,而AR类则不一定构成一个完整的领域模型。eg : 产品的数据存放在多张张表内:product_a和product_b等,因此会有多个AR类对应这些表;同时,可以引入一个名为“Product”的Domain类,它代表了一个完整的产品(领域模型)。Domain类可以基于底层AR类中一个(一般来说是基于主表)。目录结构目录结构如下所示: 详细说明 如上图所示,各个层次Controller、Service、Transformer、Model、Repository都有自己相应的目录Controllers目录说明(Controller层) Controller层,所有api的控制器放在该目录下,按版本分类(V1,V2...),版本目录下按照业务分类Controller层的职责: 校验输入处理请求&构造响应调用Transformer层、Service层、Repository层,但不应该在Controller中包含任何业务逻辑在各个版本目录之下(V1,V2...),按照业务将Controller分到不同的子目录中(eg:Blog,Marketing...),而不是按照数据库进行划分,虽然按照业务划分与按照数据库划分的结果可能一样每个版本目录下有一个版本控制器(eg:V1Controller),该版本下的所有控制器需要继承自该控制器。版本控制器必须继承自AppHttpControllersApiController按照业务划分的控制器子目录中应该有一个控制器基类(eg:BaseController),所有该目录下的控制器继承自该基类控制器Common目录说明 Common目录用于放置一些在整个项目中都可以使用的通用代码,通常这些代码不应该包含特定的业务逻辑子目录Components用于放置组件代码(注意:这些组件代码不应该继承自框架代码/第三方代码,否则应该将其放置到Extensions目录)。通常这些代码能提供一个特定的功能,但又不依赖框架本身,可以作为其他项目的第三方包使用子目录Extensions用于放置扩展了框架代码/第三方代码原有功能的代码(通常意味着继承自框架代码/第三方代码),注意与Components区分子目录Enum用于放置“常量定义”的代码子目录Helpers用于放置一些工具类,工具类中通常会提供一些静态方法,方便调用子目录Scopes用于放置与Eloquent ORM相关的Scopes定义子目录Lib用于存放一些底层的库文件Models目录说明(Model层) Model层,所有的模型类放置在该目录下。通常按数据库进行分类(eg: DbBlog)Model层的职责(继承自Eloquent class时): 对应一张数据库表,一个model实例表示表中一条记录处理property ,如$db, $table,$fillable等;处理scopeAccessors & Mutators : 在从model实例中获取或存储属性时对其进行格式化关联关系配置: 使用hasMany()、belongsTo()等model本身行为的代码(即领域逻辑代码,属于业务逻辑的一部分),包括了执行model在运行时的状态变化,如status由valid变换成invalidModel层的职责(不继承自Eloquent class时): 作为一个领域类,包含领域逻辑当一个完整的领域类被分割成多个数据库表存储在数据库中时,可以在各数据库目录(eg:DbBlog)下创建Domain目录,用于存放完整的领域类。所有对应数据库表的Model应该间接继承自AppModel。每个数据库目录下(eg: DbBlog)应该包含一个BaseModel(代表该数据库),其他Model继承自该BaseModel注意:对数据库表进行“增删改查”的操作代码请不要放置到Model,应该将“增删改查”的代码放置到Repository层Repositories目录说明(Repository层) Repository层,所有仓库类放置在该目录下。通常按照业务/数据库进行划分Repository层的职责: 仅包含对数据库直接进行增删改查操作的代码,辅助Model层(除此之外请不要放置其他代码;通常增删改的逻辑比较单一,而查则会有多种情况,将各种查询逻辑在此处实现)Repository层仅包含直接对数据库进行操作的代码,其他涉及外部调用等功能的代码应该考虑放置在Service层中。所有的仓库类应该继承自AppRepository类。Services目录说明(Service层) Service层,所有的服务类放置在该目录下。通常按业务进行分类Service层的职责: 处理牵涉到的外部行为:如发送邮件,使用外部API(如使用队列,调用thrift,调用其他团队的服务等)包含业务逻辑(主要是工作流逻辑(workflow logic),即完成某个任务的具体流程):service层是业务逻辑存在的主要地方,辅助Controller层;当需要对数据库进行增删改查时,则应该调用相应的Repository层所有的服务类都应该继承自AppService类Transformers目录说明(Transformer层) Transformer层,所有的转换类放置在该目录下。通常按照业务进行分类。Transformer层的职责: 处理显示逻辑管理API接口的输出(使接口的输出与底层的Service,Repository,Model等解耦,这样即使底层数据库表进行了修改,也可以不影响接口的使用)所有的转换类都应该继承自AppTransformer类响应注意 : 这里讨论的响应格式指的是应用业务相关的响应,由第三方提供的api接口的响应不纳入处理范围(eg:laravel passport提供的响应,swagger提供的响应) 响应分类成功类响应:http响应码介于200~300。返回此类响应表示服务器完整处理了该请求,没有未捕捉处理的异常或错误。(除了正常情况,在业务逻辑处理失败时,也会返回此类响应,同时会带上相应的业务处理失败信息)失败类响应 : http响应码不介于200~300。返回此类响应表示服务器抛出了未捕捉处理的异常或错误。响应例子成功类响应1.业务逻辑处理成功 2.业务逻辑处理失败 结构如上图所示:结构与业务逻辑处理成功是一样。区别在于成功时的code为0,失败时则为相应的错误码,code的取值为为app\Common\Enum\ErrorCode.php中的业务级错误码(见下面的错误码)。 失败类响应失败响应的格式配置在文件config/api.php中(关键词为:errorFormat)。主要包括了message、errors、code、status_code、debug。有些信息在生产环境不会展示。 响应格式化处理的思路响应格式化处理的大致思路:对特定的请求(对此类请求做标记)的处理结果,在返回给用户时进行拦截(使用事件机制),对原有响应进行格式化处理。响应的代码: App\Http\Middleware\BusinessFormatOutput : 路由中间件,在某些路由放置该中间件,则标记该请求,表明其响应需要进行格式化处理App\Listeners\AddBusinessStatusToResponse : 事件handler,处理由dingo触发的ResponseWasMorphed事件,对响应进行格式化处理App\Http\Controllers\ApiController.php文件中的常量BusinessStatusHeader,通过响应中的header为中介,将业务逻辑处理结果传递到2中的事件handler中,并最终构成格式化响应。错误码错误码相关的代码文件为:app\Common\Enum\ErrorCode.php错误码格式:A-BB-CCC A : 表示错误级别,0代表成功,1代表系统级错误,2代表服务(业务)级错误;B : 表示项目/模块/分类;C : 具体错误编号;不同错误级别错误码的使用: ...

May 27, 2019 · 1 min · jiezi

laravel-调度任务没有执行的问题

1.调度任务命令如下:$schedule->command('emails:send')->withoutOverlapping(); 说明:withoutOverlapping 这个命令的作用就是当一个进程还没跑完,不会开启新的进程。其机制就是开启明亮的时候会在项目的storage/framework/cache目录中添加一个文件,如果进程卡住或者未进行完成的时候,这个文件就会陷入死循环,一直执行该进程,等到进程执行完毕之后,会删除相对应的缓存文件,开始下一个进程。 简单理解就是加上withoutOverlapping 会引起阻塞,只有完成的任务才会继续下面的进程

May 27, 2019 · 1 min · jiezi

LaravelLayimGatewayWorker实现实时聊天功能

LayIM客户端源码 LayIM服务端源码 Laravel+Layim+GatewayWorker实现实时聊天功能它是什么?基于wbsocket的有前端有后端的支持分布式部署的网页版实时聊天。 有啥功能?想象一下,精简版的qq临时会话加好友单聊群聊消息实时推送查看聊天记录效果预览 体验地址http://laravel-layim.jc91715.top/pc 体验账号 1111@qq.com 111111112222@qq.com 111111113333@qq.com 11111111介绍1 Layim 是什么? 想象一下,没有后台的qq的是什么样子,介绍地址http://layim.layui.com/,不开源,需要授权奥 2 GatewayWorker 是什么? 我的理解是这样的,它是一个容器,你给它发送消息,它可以把消息,发送到你想要的地方,支持分布式部署,详细请看文档手册http://doc2.workerman.net/ 3 结语Layim 良心产品,它已经把后端的数据结构抽象出来了,很容易去推算出后端的表结构是什么样子。个人认为 GatewayWorker 就是为Layim的后端而生的,简直是无缝结合起来。也可以使用第三方如环信等产品。如果你想自己把握数据的私密性还是自建的比较好。个人只在当中使用laravel把Layim 和GatewayWorker 串连起来,解决了Layim 没有后端的尴尬境地。当然Layim它的商业应用使用最多的应该是它的客服窗口,就是右下角的那个客服窗口,它的优势可能并不在于全部功能。对于开发者来说,这样的一个好的产品,不把它给后台完善了,总有点缺憾不是 让网页版实时聊天焕发第二春难免疏漏不足之处,敬请批评改正如果对你有所帮助,请喝个咖啡

May 26, 2019 · 1 min · jiezi

深入理解控制反转IoC和依赖注入DI

容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描述(类、接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” 、“依赖注入(DI)”。本文就从这里开始。IoC 容器, laravel 的核心Laravel 的核心就是一个 IoC 容器,根据文档,称其为“服务容器”,顾名思义,该容器提供了整个框架中需要的一系列服务。作为初学者,很多人会在这一个概念上犯难,因此,我打算从一些基础的内容开始讲解,通过理解面向对象开发中依赖的产生和解决方法,来逐渐揭开“依赖注入”的面纱,逐渐理解这一神奇的设计理念。 本文一大半内容都是通过举例来让读者去理解什么是 IoC(控制反转) 和 DI(依赖注入),通过理解这些概念,来更加深入。更多关于 laravel 服务容器的用法建议阅读文档即可。 IoC 容器诞生的故事讲解 IoC 容器有很多的文章,我之前也写过。但现在我打算利用当下的灵感重新来过,那么开始吧。 超人和超能力,依赖的产生!面向对象编程,有以下几样东西无时不刻的接触:接口、类还有对象。这其中,接口是类的原型,一个类必须要遵守其实现的接口;对象则是一个类实例化后的产物,我们称其为一个实例。当然这样说肯定不利于理解,我们就实际的写点中看不中用的代码辅助学习。 怪物横行的世界,总归需要点超级人物来摆平。我们把一个“超人”作为一个类, class Superman {}我们可以想象,一个超人诞生的时候肯定拥有至少一个超能力,这个超能力也可以抽象为一个对象,为这个对象定义一个描述他的类吧。一个超能力肯定有多种属性、(操作)方法,这个尽情的想象,但是目前我们先大致定义一个只有属性的“超能力”,至于能干啥,我们以后再丰富: class Power { /** * 能力值 */ protected $ability; /** * 能力范围或距离 */ protected $range; public function __construct($ability, $range) { $this->ability = $ability; $this->range = $range; }}这时候我们回过头,修改一下之前的“超人”类,让一个“超人”创建的时候被赋予一个超能力: class Superman{ protected $power; public function __construct() { $this->power = new Power(999, 100); }}这样的话,当我们创建一个“超人”实例的时候,同时也创建了一个“超能力”的实例,但是,我们看到了一点,“超人”和“超能力”之间不可避免的产生了一个依赖。 所谓“依赖”,就是 “我若依赖你,我就不能离开你”。在一个贯彻面向对象编程的项目中,这样的依赖随处可见。少量的依赖并不会有太过直观的影响,我们随着这个例子逐渐铺开,让大家慢慢意识到,当依赖达到一个量级时,是怎样一番噩梦般的体验。当然,我也会自然而然的讲述如何解决问题。 ...

May 24, 2019 · 4 min · jiezi

ThinkPHP51-源码浅析二自动加载机制

继 生命周期的第二篇,大家尽可放心,不会随便鸽文章的第一篇中,我们提到了入口脚本,也说了,里面注册了自动加载的功能 本文默认你有自动加载和命名空间的基础。如果没有请 看此篇文章 php 类的自动加载与命名空间自动加载机制php 的自动加载是 Loader 类中实现的,这个类在 base.php 中被引入 //base .php// 载入Loader类require __DIR__ . '/library/think/Loader.php';// 注册自动加载Loader::register();我们程序在这里执行了 Loader 中静态方法 ,同时这也是一个全部的类register() 我们进入 Loader.php ,按照上面执行顺序看看其核心是什么? register()方法执行流程 注册系统自动加载此方法行数过长,我们一点一点来分析 // 注册系统自动加载 spl_autoload_register($autoload ?: 'think\\Loader::autoload', true, true);这就是注册我们的自动加载函数,$autoload 这个变量是传的参数,考虑到你可以自己实现自己的加载类,为了方便拓展,TP可以让你自己实现自己的类加载方法。 如果不了解这个函数的同学,请看文章最顶部的那个连接,上面有详细讲解。 Composer自动加载支持$rootPath = self::getRootPath(); self::$composerPath = $rootPath . 'vendor' . DIRECTORY_SEPARATOR . 'composer' . DIRECTORY_SEPARATOR; // Composer自动加载支持 if (is_dir(self::$composerPath)) { if (is_file(self::$composerPath . 'autoload_static.php')) { require self::$composerPath . 'autoload_static.php'; // 获取当前加载的所有类 $declaredClass = get_declared_classes(); $composerClass = array_pop($declaredClass); foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) { if (property_exists($composerClass, $attr)) { self::${$attr} = $composerClass::${$attr}; } } } else { self::registerComposerLoader(self::$composerPath); } }为了支持 composer 拓展,在自动注册时候,把composer 也顺带一起注册了,方便对拓展的调用。 ...

May 23, 2019 · 3 min · jiezi

laraval模板方法设计模式实现服务容器

1、第一点,首先说明设计模式跟实现服务容器没关系之所以采用这个标题,是因为自己当初犯了这种错误,希望新学laravel的人不要犯这种跟我一样的错误。 2、我定义了接口,同时抽象类继承接口,其他具体实现类继承抽象类。当我执行代码首次失败时,我去网上搜寻答案,他们说,你这种实现模式,就在注册服务时,应该注册抽象类,而不是接口类。 但是他们这种是不对的,事实证明我的错误原因的根本不在这里。所以我想强调,如果你也这样做,那么,可以采用接口类。 3、我在抽象类中定义了构造方法,想让所有继承抽象类的子类也都继承它的构造方法。但是我犯的错误是,我的构造函数用了protected,所以子类无法继承。当我把我的构造函数改成public时,才正确。

May 23, 2019 · 1 min · jiezi

10Laravel使用视图组合器View-composer

Laravel的视图组合器很有用,在网站中, 许多页面的侧边栏是相同的,将侧边栏公用部分提取出来肯定是必须的,让Controller专注于业务逻辑。参考:https://laravel.com/docs/5.5/... 创建一个新的 provider类 ViewComposerServiceProvider php artisan make:provider ViewComposerServiceProvider编辑ViewComposerServiceProvider类文件中boot()方法,添加如下代码: // 参数'*':代表所有视图,其实可以指定视图// \App\Http\ViewComposers\PublicComposer:公共视图的业务逻辑,目录位置是自定义的\View::Composer('*', '\App\Http\ViewComposers\PublicComposer');在ConfigApp.php配置文件中配置$provider数组,加入自定义的ViewComposerServiceProvider类 App\Providers\ViewComposerServiceProvider::class编辑AppHttpViewComposersPublicComposer类文件中compose()方法,添加公共数据的业务逻辑 public function compose(View $view){ $categories = $this->cache('categories', function () { // 获取数据逻辑 return Category::all(); }, 60*24); $tags = $this->cache('tags', function () { return Tag::all(); }, 60*24); // $view->with()方法绑定参数到视图 $view->with(compact('categories', 'tags'));}// 封装一个缓存处理方法private function cache($key, $callback, $time = 60){ $key_result = []; if (Cache::has($key)) { $key_result = Cache::get($key); } else { $key_result = $callback(); Cache::put($key, $key_result, $time); } return $key_result;}原文链接:http://www.mi360.cn/articles/4 ...

May 21, 2019 · 1 min · jiezi

laravel-Hui-基础后台管理系统

laravel_quick_admin项目地址:https://github.com/tsmliyun/l...项目实例: 背景起这个项目的初衷是,对于一个后台管理系统,登陆、注销、权限管理等都是些公用的模块,完全可以封装成一个基础项目,每次新的项目基于基础项目上开发即可,节约时间,提高开发效率。 功能模块登陆找回密码修改密码注销管理员管理权限管理角色管理支持多语言代码模块routecontrollerservicemodellogrequestRepository (关于这个仁者见仁智者见智吧)项目搭建比较简单,主要以下几步 composer install修改.env文件相关配置执行laravel_quick_admin/laravel_quick_admin.sql文件中的sql语句展望后续会更新出一版 前后端分离的基础后台框架,敬请期待。 感谢laravel -- 艺术家最爱的框架 H-ui -- 轻量级前端框架

May 21, 2019 · 1 min · jiezi

Laravel-队列-database-驱动今天刚学习了队列记录下笔记

刚学习了laravel队列,把笔记记一下。 1.第一步配置(.env)QUEUE_CONNECTION=database2.database 驱动设置第一步:生成 jobs 数据迁移表 php artisan queue:table效果如下:第二步: 创建jobs表,执行迁移命令 php artisan migrate效果如下: 3.模拟数据第一步: 进入 thinker php artisan thinker第二步:创建数据 (thinker命令) factory(App\User::class,10)->create();// 创建10个用户打开users表 就能看到 创建的10 个新用户 4.创建 Jobs及编写第一步:创建 php artisan make:job Email此时能在 app 目录下生成个 Jobs 文件夹 及我们创建的 Email.php文件 效果如下: 第二步:编写Email.php <?phpnamespace App\Jobs;use App\User;use Illuminate\Bus\Queueable;use Illuminate\Queue\SerializesModels;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Support\Facades\Log;class Email implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; //定义 public $user; /** * Create a new job instance. * * * @return void */ public function __construct(User $user) { //赋值 $this->user = $user; } /** * Execute the job. * * @return void */ public function handle() { //打印日记 Log::info('发送的邮件是:'.$this->user->email); }}6. 创建控制器,分发任务第一步:创建Usercontroller控制器 ...

May 15, 2019 · 1 min · jiezi

Lumen-报错提示-实例不了-Response-类的问题

今天使用Lumen的时候,用到了Response类,很奇怪提示:Target [Illuminate\Contracts\Routing\ResponseFactory] is not instantiable.大概就是说实例不了Response 类,那怎么解决呢?我们以一个全新的Lumen项目来说1.我在web.php写了个路由<?php/*|--------------------------------------------------------------------------| Application Routes|--------------------------------------------------------------------------|| Here is where you can register all of the routes for an application.| It is a breeze. Simply tell Lumen the URIs it should respond to| and give it the Closure to call when that URI is requested.|*/use Illuminate\Support\Facades\Response;$router->get('/', function () use ($router) { return Response::json('123456',200);});然后访问这个路由报错如下(也就是我们要解决的错误): 2.解决办法2.1 打开项目根目录下的 bootstrap/app.php //找到这两行把注释去掉 $app->withFacades(); $app->register(App\Providers\AppServiceProvider::class);2.2 找到 项目根目录下的 app/Providers/AppServiceProvider.php <?phpnamespace App\Providers;use Illuminate\Routing\ResponseFactory;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ /** * Register any application services. * * @return void */ public function register() { }}在 register 注册 ResponseFactory 修改如下: ...

May 15, 2019 · 1 min · jiezi

使用-seed-命令创建模拟数据学习笔记

在开发环境中,我们经常会使用 “模拟数据” 来测试我们应用,在laravel 中 提供了 ”数据填充“来帮助我们实现这个需求。我们现在就来用这个功能来创建 20个用户... 1.使用 artisan 命令生成 用户表1.1 打开新创建的laravel项目 database/migrations目录 下可以发现 两个文件 一个是创建用户表的,一个是创建确认密码表的(图中没看到是因为我删除了) 1.2 我们可以打开这个文件瞧瞧 (根据实际情况修改,这里我就不修改了) <?phpuse Illuminate\Support\Facades\Schema;use Illuminate\Database\Schema\Blueprint;use Illuminate\Database\Migrations\Migration;class CreateUsersTable extends Migration{ /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); }}1.3 执行 artisan 命令 生成表 ...

May 15, 2019 · 2 min · jiezi

Laravel-队列-beanstalkd-驱动

上一篇文章讲了 database 通道 建议先去看上篇文章 1.beanstalkd 与 databasedatabase:把队列添加到数据表中beanstalkd:把队列添加到内存中 2.安装sudo apt-get install beanstalkd3.依赖安装cd 到项目根目录 composer require pda/pheanstalk4.修改 .envQUEUE_CONNECTION=beanstalkd6.访问路由(数据将写入到内存中)7.执行命令php artisan queue:work8.打开日志文件打印的消息: 完结 下一篇文章 讲 beanstalkd_console能更直观的看到数据添加到内存中

May 15, 2019 · 1 min · jiezi

云社区技术沙龙深圳站与大咖聊聊互联网架构

5月25日,在深圳腾讯滨海大厦,云+社区邀您参加《互联网架构》沙龙活动,一起探讨技术架构发展趋势,畅想未来。 技术不断演变的过程中,技术架构对于企业来说起到什么作用? 本期沙龙将邀请腾讯的技术专家分享关于技术架构、落地实践案例、无服务器云函数架构、海量存储系统架构等话题,从技术角度看架构发展,带来丰富的实践经验内容,让你对技术架构有更深入的了解和认识 活动信息 点此报名

May 10, 2019 · 1 min · jiezi

Laravel-的缓存源码解析

Last-Modified: 2019年5月10日14:17:34 前言Laravel 支持多种缓存系统, 并提供了统一的api接口. (Laravel 5.5)默认支持的存储驱动包括如下: file (默认使用)apcarray (数组, 测试用)database (关系型数据库)memcachedredis默认的缓存配置文件在 config/cache.php 参考链接: https://learnku.com/docs/lara...https://www.jianshu.com/p/46a...使用直接使用Laravel为我们提供的Facade use Illuminate\Support\Facades\Cache;$cache = Cache::get('key');支持的大部分方法: Cache::put('key', 'value', $minutes);Cache::add('key', 'value', $minutes);Cache::forever('key', 'value');Cache::remember('key', $minutes, function(){ return 'value' });Cache::rememberForever('key', function(){ return 'value' });Cache::forget('key');Cache::has('key');Cache::get('key');Cache::get('key', 'default');Cache::get('key', function(){ return 'default'; });Cache::tags('my-tag')->put('key','value', $minutes);Cache::tags('my-tag')->has('key');Cache::tags('my-tag')->get('key');Cache::tags('my-tag')->forget('key');Cache::tags('my-tag')->flush();Cache::increment('key');Cache::increment('key', $amount);Cache::decrement('key');Cache::decrement('key', $amount);Cache::tags('group')->put('key', $value);Cache::tags('group')->get('key');Cache::tags('group')->flush();其他使用方法请参照官方翻译(中文)文档: https://learnku.com/docs/lara... 源码Laravel 中常用 Cache Facade 来操作缓存, 对应的实际类是 Illuminate\Cache\CacheManager 缓存管理类(工厂). Cache::xxx()我们通过 CacheManager 类获取持有不同存储驱动的 Illuminate\Cache\Repository 类 CacheManager::store($name = null)Repository 仓库类代理了实现存储驱动接口 Illuminate\Contracts\Cache\Store 的类实例. Cache Facade首先从 Cache Facade 开始分析, 先看一下其源码: ...

May 10, 2019 · 4 min · jiezi

Laravel-基于redis队列的解析

Last-Modified: 2019年5月10日11:44:18 参考链接使用 Laravel Queue 不得不明白的知识Laravel 队列文档本文环境Laravel 5.5队列 Redis为什么使用队列使用队列的目的一般是: 异步执行出错重试解释一下: 异步执行: 部分代码执行很耗时, 为了提高响应速度及避免占用过多连接资源, 可以将这部分代码放到队列中异步执行. Eg. 网站新用户注册后, 需要发送欢迎的邮件, 涉及到网络IO无法控制耗时的这一类就很适合放到队列中来执行.出错重试: 为了保证一些任务的正常执行, 可以将任务放到队列中执行, 若执行出错则可以延迟一段时间后重试, 直到任务处理成功或出错超过N次后取消执行. Eg. 用户需要绑定手机号, 此时发送短信的接口是依赖第三方, 一个是不确定耗时, 一个是不确定调用的成功, 为了保证调用成功, 必然需要在出错后重试Laravel 中的队列以下分析默认使用的队列及其配置如下 默认队列引擎: redis 通过在 redis-cli 中使用 monitor 命令查看具体执行的命令语句默认队列名: default分发任务此处以分发 异步通知(class XxxNotification implement ShouldQueue)为例. 在Laravel中发起异步通知时, Laravel 会往redis中的任务队列添加一条新任务 redis 执行语句 redis> RPUSH queues:default{ "displayName": "App\\Listeners\\RebateEventListener", "job": "Illuminate\\Queue\\CallQueuedHandler@call", "maxTries": null, "timeout": null, "timeoutAt": null, "data": { "commandName": "Illuminate\\Events\\CallQueuedListener", "command": "O:36:\"Illuminate\\Events\\CallQueuedListener\":7:{s:5:\"class\";s:33:\"App\\Listeners\\RebateEventListener\";s:6:\"method\";s:15:\"onRebateCreated\";s:4:\"data\";a:1:{i:0;O:29:\"App\\Events\\RebateCreatedEvent\":4:{s:11:\"\u0000*\u0000tbkOrder\";O:45:\"Illuminate\\Contracts\\Database\\ModelIdentifier\":3:{s:5:\"class\";s:19:\"App\\Models\\TbkOrder\";s:2:\"id\";i:416;s:10:\"connection\";s:5:\"mysql\";}s:15:\"\u0000*\u0000notifyAdmins\";b:1;s:13:\"\u0000*\u0000manualBind\";b:0;s:6:\"socket\";N;}}s:5:\"tries\";N;s:9:\"timeoutAt\";N;s:7:\"timeout\";N;s:6:\"\u0000*\u0000job\";N;}" }, "id": "iTqpbeDqqFb3VoED2WP3pgmDbLAUQcMB", "attempts": 0}上面的redis语句是将任务信息(json格式) rpush 到 redis 队列 queues:default 的尾部. ...

May 10, 2019 · 2 min · jiezi

网上平台系统维护审核风控不给提款怎么解决

一般客服推辞不给出款的借口如下:你的账户异常登录、网站维护、网站出款端口维护、账户涉嫌套利、系统自动抽查审核、网站抽查审核、账户违规下注、银行系统维护等等借口不给你出款甚至冻结你账户。1:如果你真的赢太多了,他们不给你出款,这个时候无论理由是系统审核,还是其他任何理由,你就不用考虑了,直接把钱输回去提本金出来,因为你拖久了可能本金也提不了,到那你时候你出款会更加麻烦。2:如果你赢得不是特别多的话你或许可以以介绍朋友去的理由诱惑客服,让他给你出款。3:实在是没有办法就找那些可以攻击黑网的朋友,攻击网站出款,当然了什么藏分出款的,什么第三方出款的你们要是找的话也要看清楚是不是真有那个实力,千万不要又去找到一个打着出黑口号黑钱的骗子,款没有出出来还要教什么出款手续费,出款材料费,这样就真的是太冤了。不要等到自己的账号被冻结了,那个时候谁也帮不了你,只要账号可以正常登录额度可以转换就有办法,不要被坑了,及时挽回自己的财产损失遇到这种情况的可以叩【748590857】童位,你不试试怎么会知道拿不回来呢?

May 9, 2019 · 1 min · jiezi

PHP-74-新语法箭头函数

短闭包,也叫做箭头函数,是一种用 php 编写的短函数.当向函数中传递闭包时,这个功能是非常有用的,比如使用 array_map 或是 array_filter函数时. 这就是它们看起来的样子: // Post 对象的集合$posts = [/* … */];$ids = array_map(fn($post) => $post->id, $posts);而以前,你必须这样写: $ids = array_map(function ($post) { return $post->id;}, $posts);我们来总结一下短闭包函数如何使用. 在 PHP 7.4 里可用以 fn 关键字开头只能包含 一个 表达式, 即返回表达式return 关键字可忽略参数和返回类型均可做类型暗示上面示例更严格的类型限定写法可写作: $ids = array_map(fn(Post $post): int => $post->id, $posts);有两点需要提及: 还允许使用扩展操作符允许引用,两个参数都可以作为返回值假如你想要通过引用的方式返回结果,应该使用以下语法: fn&($x) => $x简而言之,除了只允许一个表达式以外,简短的闭包和普通闭包的功能是一样的。 单行你应该正确的理解它:短闭包只能有一个表达式。这意味着闭包体中不能有多行。 原因如下:短闭包的目的是为了减少冗余。当然,在任何情况下, fn 都比 function 短。然而, RFC 的创建者 Nikita Popov 认为,如果你要处理的是多行表达式的函数,那么使用闭包获得的益处就更少了。 毕竟,多行闭包的定义已经很冗余了,所以,有和没有这2个关键字( function 和 return )将不会有太大区别。 你是否同意这个观点取决于你自己。虽然我可以在我的项目中想到很多单行闭包的场景,但也有很多多行闭包的情况,从个人角度,我会喜欢这些情况下的简短语法。 ...

May 9, 2019 · 1 min · jiezi

使用-Laravel-Passport-为你的-REST-API-增加用户认证功能

在本教程中,我们将了解如何在 Laravel 应用中使用 laravel passport 认证。 我们还将使用 Laravel Passport 认证 构建一个简单的产品 (创建, 查询, 更新和删除 )。 Laravel 已经提供了传统的登录表单身份验证,但是如果你想使用 APIs 呢?APIs 使用令牌来验证用户,因为它们不使用会话。当用户通过 API 登录时,会生成令牌并将其发送给用户,该用户可用于身份验证。Laravel 提供 Passport ,可以毫无困难地使用 API 认证。 让我们看看如何在 Laravel 应用程序中设置和配置用于 API 认证和 RESTful APIs 的 Laravel Passport 。 创建一个新的应用我们新建一个Laravel 应用。 执行下面的命令就可以创建一个全新的laravel应用。 composer create-project --prefer-dist laravel/laravel passport安装Passport 扩展我们使用composer 安装Passport 扩展。 执行下面的命令来安装这个扩展。 composer require laravel/passportLaravel配置PassportLaravel Passport 扩展需要做一些配置。 服务提供者我们使用的 Laravel 5.6最新版本,它可以使用包发现并自动注册服务。如果你使用 laravel 5.4 或者 更低版本,你需要在 config/app.php 文件中为Passport注册服务。就这样,在这个文件中的providers数组中添加注册服务。 'providers' => [ .... Laravel\Passport\PassportServiceProvider::class,]迁移和安装在.env 文件中设置数据库凭据。 Laravel Passport 提供了需要在我们的数据库中的护照表的迁移文件。 Passport迁移用于存储令牌和客户端信息。 运行migration 命令以将架构迁移到数据库。 ...

May 7, 2019 · 4 min · jiezi

Wizard-开源文档管理系统10发布啦

Wizard 是一款开源文档管理系统,项目地址为 https://github.com/mylxsw/wizard。这个项目是 我 在2017年就开始开发的,起初只是想做一款能够在公司内部把Swagger文档管理起来的工具,但在这近两年的时间里,一直断断续续的为其添加各种功能,现在终于下决心发布1.0版本了,目前支持三种类型的文档管理 Markdown:也是Wizard最主要的文档类型,研发团队日常工作中交流所采用的最常用文档类型,在 Wizard 中,对 Editor.md 项目进行了功能扩展,增加了文档模板,Json 转表格,图片粘贴上传等功能 Swagger:支持 OpenAPI 3.0 规范,嵌入了 Swagger 官方的编辑器,通过定制开发,使其融入到 Wizard 项目当中,支持文档模板,全屏编辑,文档自动同步功能 Table:这种文档类型是类似于 Excel 电子表格,采用了 x-spreadsheet 项目,将该项目嵌入到了 Wizard 中,目前还不是很完善 目前主要包含以下功能 Swagger,Markdown,Table 类型的文档管理文档修改历史管理文档修改差异对比用户权限管理项目分组管理LDAP 统一身份认证文档搜索,标签搜索阅读模式文档评论消息通知文档分享统计功能如果想快速体验一下Wizard的功能,有两种方式 在线体验请访问 http://wizard.aicode.cc/ ,目前只提供部分功能的体验,功能预览和使用说明请参考 Wiki。使用Docker来创建一个完整的Wizard服务进入项目的根目录,执行 docker-compose up,就可以快速创建一个Wizard服务了,访问地址 http://localhost:8080 。 起源为了鼓励大家写开发文档,最开始我们选择了 ShowDoc 项目来作为文档管理工具,当时团队规模也非常的小,大家都是直接用 Markdown 写一些简单的开发文档。后来随着团队的壮大,前后端分离,团队分工的细化,仅仅采用 Markdown 开始变得捉襟见肘,这时候,我们首先想到了使用开源界比较流行的 Swagger 来创建开发文档。但是 Swagger 文档多了,总得有个地方维护起来吧? 项目中的文档仅仅用Swagger也是不够的,它只适应于API文档的管理,还有很多其它文档,比如设计文档,流程图,架构文档,技术方案,数据库变更等各种文档需要一起维护起来。因此,我决定利用业余时间开发一款 支持 Markdown 和 Swagger 的文档管理工具,也就是 Wizard 项目了。 起初打算用 Go 语言来开发,但是没过几天发现使用 Golang 来做 Web 项目开发效率太低(快速开发效率,并非指性能,Golang做API接口开发还是很不错的),很多常用的功能都需要自己去实现,遂放弃使用 Golang,转而使用 PHP 的 Laravel 框架来开发。所以虽然项目创建的时间为 2017年7月27日,但是实际上真正开始的时间应该算是 2017年7月31日。 ...

May 6, 2019 · 1 min · jiezi

XKNote-一个集各种神奇功能的云笔记

XK-Note一个集各种神奇功能的云笔记 前言博主是个计科的大学生,所以经常需要将一些不太理解的代码或者经验记录下来,纸质笔记对一些经验还好,一旦涉及代码。。。,所以博主的笔记都是电子的,在弄好这个笔记时使用的是Typora,确实非常好用,但是有个硬伤,同步不便,到机房上课的时候笔记就派不上用场,并且查看还要使用支持Markdown的编辑器。可谓苦不堪言,直到我在Github上看到了Editor.md这个项目,于是便开始了Coding。 简介 IntroductionXK-Note = Laravel . ZUI . Editor.md;一个由上方代码组成,集各种神奇功能的云笔记。 特性 Feature[云存储] 云端撰写笔记,随时保存,多端同步。[跨平台] 多平台支持,撰写查阅只需一个浏览器,无惧任何不兼容情况。[响应式] 所有页面均采用响应式设计,即使尺寸极小的设备也能保持良好的体验。[在线浏览] 拥有独立的浏览模式,查看笔记不再困扰。[Git同步支持] 独有的Git支持,支持版本控制,无惧误操作,随时从旧版本恢复笔记。[浏览器临时保存] 独有的浏览器端保存功能,即使断网了也能安心写作,无惧任何网络波动。[多用户] 笔记主要面向个人使用,但是也支持多人同时使用,每个用户的笔记互相隔离保存,无需担心笔记泄露。[导出笔记] 支持多种导出格式,保存为MD文件,html文件,由本地即时生成,无需繁琐的操作。[多种模式] 拥有多种模式,写作,预览,阅读,满足各种人的需求。还有多种神奇的功能等待你的发掘。演示 DemoXK-Note账号: demo@ixk.me密码: demo 安装 Install前往 Release 下载,然后上传至服务器,并解压到网站根目录安装依赖# Ubuntu/Debian 其他系统请自行查阅sudo apt-get install curl gitcurl -sS https://getcomposer.org/installer | phpsudo mv composer.phar /usr/local/bin/composer进入网站根目录,并执行以下命令composer installphp artisan storage:link将根目录下的xknote.sql文件导入到数据库中,并确认是否导入成功修改.env文件,将数据库信息填入.env文件中,并关闭调试模式APP_DEBUG=false修改网站的运行目录到public打开网站,注册一个账户,并确认账户id是否为1(账户id为1代表管理员)enjoy文档 Doc暂无 Githubhttps://github.com/syfxlin/xk... 求 star = ̄ ̄= 维护者 MaintainerXK-Note 由 Otstar Lin和下列贡献者的帮助下撰写和维护。 Otstar Lin - Personal Website · Blog · Github许可证 License 根据 Apache License 2.0 许可证开源。 ...

May 6, 2019 · 1 min · jiezi

Laravel整合PHPSocketIo实现web消息推送

PHPSocket.IO,PHP跨平台实时通讯框架PHPSocket.IO是PHP版本的Socket.IO服务端实现,基于workerman开发,用于替换node.js版本Socket.IO服务端。PHPSocket.IO底层采用websocket协议通讯,如果客户端不支持websocket协议, 则会自动采用http长轮询的方式通讯。环境Ubuntu 18Laravel 5.8PHPSocket.IO 1.1安装依赖composer require workerman/phpsocket.iocomposer require guzzlehttp/guzzle启动程序整合到artisan命令中创建文件命令php artisan make:command MsgPush app/Console/Commands/MsgPush.php <?phpnamespace App\Console\Commands;use Illuminate\Console\Command;use Workerman\Worker;use Workerman\Lib\Timer;use PHPSocketIO\SocketIO;class MsgPush extends Command{ protected $signature = 'msg-push {action=start : start | restart | reload(平滑重启) | stop | status | connetions} {--d : deamon or debug}'; protected $description = 'web消息推送服务'; // 全局数组保存uid在线数据 private static $uidConnectionCounter = []; // 广播的在线用户数,一个uid代表一个用户 private static $onlineCount = 0; // 广播的在线页面数,同一个uid可能开启多个页面 private static $onlinePageCount = 0; //PHPSocketIO服务 private static $senderIo = null; public function __construct() { parent::__construct(); } /** * 根据脚本参数开启PHPSocketIO服务 * PHPSocketIO服务的端口是`2120` * 传递数据的端口是`2121` */ public function handle() { global $argv; //启动php脚本所需的命令行参数 $argv[0] = 'MsgPush'; $argv[1] = $this->argument('action'); // start | restart | reload(平滑重启) | stop | status | connetions $argv[2] = $this->option('d') ? '-d' : ''; // 守护进程模式或调试模式启动 // PHPSocketIO服务 self::$senderIo = new SocketIO(2120); // 客户端发起连接事件时,设置连接socket的各种事件回调 self::$senderIo->on('connection', function ($socket) { // 当客户端发来登录事件时触发,$uid目前由页面传值决定,当然也可以根据业务需要由服务端来决定 $socket->on('login', function ($uid) use ($socket) { // 已经登录过了 if (isset($socket->uid)) return; // 更新对应uid的在线数据 $uid = (string)$uid; // 这个uid有self::$uidConnectionCounter[$uid]个socket连接 self::$uidConnectionCounter[$uid] = isset(self::$uidConnectionCounter[$uid]) ? self::$uidConnectionCounter[$uid] + 1 : 1; // 将这个连接加入到uid分组,方便针对uid推送数据 $socket->join($uid); $socket->uid = $uid; // 更新这个socket对应页面的在线数据 self::emitOnlineCount(); }); // 当客户端断开连接是触发(一般是关闭网页或者跳转刷新导致) $socket->on('disconnect', function () use ($socket) { if (!isset($socket->uid)) { return; } // 将uid的在线socket数减一 if (--self::$uidConnectionCounter[$socket->uid] <= 0) { unset(self::$uidConnectionCounter[$socket->uid]); } }); }); // 当self::$senderIo启动后监听一个http端口,通过这个端口可以给任意uid或者所有uid推送数据 self::$senderIo->on('workerStart', function () { // 监听一个http端口 $innerHttpWorker = new Worker('http://0.0.0.0:2121'); // 当http客户端发来数据时触发 $innerHttpWorker->onMessage = function ($httpConnection, $data) { $type = $_REQUEST['type'] ?? ''; $content = htmlspecialchars($_REQUEST['content'] ?? ''); $to = (string)($_REQUEST['to'] ?? ''); // 推送数据的url格式 type=publish&to=uid&content=xxxx switch ($type) { case 'publish': // 有指定uid则向uid所在socket组发送数据 if ($to) { self::$senderIo->to($to)->emit('new_msg', $content); } else { // 否则向所有uid推送数据 self::$senderIo->emit('new_msg', $content); } // http接口返回,如果用户离线socket返回fail if ($to && !isset(self::$uidConnectionCounter[$to])) { return $httpConnection->send('offline'); } else { return $httpConnection->send('ok'); } } return $httpConnection->send('fail'); }; // 执行监听 $innerHttpWorker->listen(); // 一个定时器,定时向所有uid推送当前uid在线数及在线页面数 Timer::add(1, [self::class, 'emitOnlineCount']); });// Worker::$daemonize = true; Worker::runAll(); } /** * 将在线数变化推送给所有登录端 * 须是public方法,可供其它类调用 */ public static function emitOnlineCount() { $newOnlineCount = count(self::$uidConnectionCounter); $newOnlinePageCount = array_sum(self::$uidConnectionCounter); // 只有在客户端在线数变化了才广播,减少不必要的客户端通讯 if ($newOnlineCount != self::$onlineCount || $newOnlinePageCount != self::$onlinePageCount) {// var_dump('emitOnlineCount: ', self::$uidConnectionCounter); //将在线数变化推送给所有登录端 self::$senderIo->emit( 'update_online_count', [ 'onlineCount' => $newOnlineCount, 'onlinePageCount' => $newOnlinePageCount ] ); self::$onlineCount = $newOnlineCount; self::$onlinePageCount = $newOnlinePageCount; } }}启动PHPSocket.Io服务#守护进程模式启动php artisan msg-push start -d#调式模式启动php artisan msg-push startweb页面resources/views/socketio.blade.php ...

May 1, 2019 · 3 min · jiezi

Laravel异常捕获处理和创建

很多开发者在开发过程中都会遇到异常,处理过程大同小异:捕获然后处理,事实上也确实是如此。但本文不打算谈太多错误与异常的原理,只是从laravel自带的Exception入手,谈一谈怎样用一个更好的方式处理错误信息。 异常先举个简单的例子,在laravel中,如果一个Model找不到或者没有,很容易就抛出一个异常,大家常见的Whoops, something went wrong诸如此类。这也只是在APP_DEBUG=false的情况下,但这并不能带给用户更有用的信息。 User::findOrFail(1);findOrFail方法在Model没有的情况下会显示:Sorry, the page you are looking for could not be found.。这是一个404的错误页面,很多时候都应该这样返回,如果我们想知道更多有用的信息呢? try...catch我在工作中也喜欢用try catch来处理可能会抛出的异常,也建议大家这么做。好处是及时捕获不可预知的错误,给用户一个更好的体验。简单的demo,如下 try { $user = User::findOrFail(1); } catch (ModelNotFoundException $exception) { return back()->withError($exception->getMessage())->withInput(); }我们也可以这样: if (! User::find(1)) { throw new ModelNotFoundException('...', 404);}自定义异常Laravel框架允许我们自定义exception执行命令 php artisan make:exception UserNotFoundException系统会自动在Exceptions目录下创建一个UserNotFoundException类,这个类继承了Exception,这就给了我们一个自由发挥的机会 namespace App\Exceptions;use Exception;class UserNotFoundException extends Exception{ public function render($request, $e) { if ($request->expectsJson()) { // 如果是ajax请求... } return redirect()->to('...'); }}判断异常在Exceptions中的Handle.php文件中,我们看到有个render()方法,这里就是我们判断自定义异常的地方 // Handle.phpif ($exception instanceof UserNotFoundException) { return $exception->render($exception, $request);}可以看到,我们只需要判断抛出的异常是否是UserNotFoundException的实例即可。而在UserNotFoundException类中,我们也可以自定义返回的数据格式和状态码等等。在工作中,我个人比较需要建一些自定义的异常类,也会很好管理。 ...

April 27, 2019 · 1 min · jiezi

译如何基于Laravel构建Vue应用一

使用Laravel能优雅的构建API并且与Vue单页面应用程序(SPA)完美结合。在本教程中,我们将展示如何启动和运行Vue路由器以及用于构建SPA的Laravel后端。我们将重点关注所需的所有部分,然后在后续教程中,我们将进一步演示如何使用Laravel作为API层。 Vue SPA如何运行的: 第一个请求命中服务器端Laravel路由器Laravel渲染SPA布局后续请求利用history.pushStateAPI进行URL导航,而无需重新加载页面Vue路由器可以配置为history模式或hash模式。默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。 这里我们使用history模式,所以需要我们需要配置一个Laravel路由,该路由将匹配所有可能的URL,具体取决于用户进入Vue SPA的路由。例如,如果用户刷新/hello路由,我们将需要匹配该路由并返回Vue SPA应用程序模板。然后,Vue路由器将确定路由并渲染相应的组件。 安装首先,我们创建一个新的Laravel项目,然后安装Vue路由器NPM包: laravel new vue-routercd vue-router# Link the project if you use Valetvalet link# Install NPM dependencies and add vue-routeryarn installyarn add vue-router # or npm install vue-router配置Vue路由器这里的 <router-view> 是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 <router-view>。 <router-view></router-view>首先,我们将更新主要的JavaScript文件resources/assets/js/app.js并配置Vue路由器。用以下内容替换app.js文件的内容: import Vue from 'vue'import VueRouter from 'vue-router'//导入并安装VueRouter插件Vue.use(VueRouter)import App from './views/App'//作为App最外层应用程序组件的组件import Hello from './views/Hello'//导入自定义Hello组件import Home from './views/Home'//导入自定义Home组件//构造一个VueRouter带有配置对象的新实例const router = new VueRouter({ mode: 'history', routes: [ { path: '/', name: 'home', component: Home }, { path: '/hello', name: 'hello', component: Hello, }, ],});const app = new Vue({ el: '#app', components: { App }, router,});然后我们需要创建一些文件,但首先,我们将介绍以下内容app.js: ...

April 25, 2019 · 2 min · jiezi

Laravel-开源学校管理系统

文章转自:https://learnku.com/laravel/t... Unified Transform 是一个开源的学校管理平台,使用Laravel 5.5(当前LTS)和 可在GitHub上获得 构建: 在较高的层次上,Unified Transform的主要功能包括: 角色: 超级管理员, 管理员, 老师, 学生, 图书管理员, 会计师出勤评分注册公告, 教学大纲图书馆考试年级账号消息这是一个大型的 Laravel 项目,因此您可能希望深入了解开源代码(包括测试),以了解它是如何构建的并提供功能。 您可以在changeweb / Unifiedtransform上了解有关此应用程序的更多信息并查看GitHub上的源代码。 文章转自:https://learnku.com/laravel/t... 更多文章:https://learnku.com/laravel/c...

April 24, 2019 · 1 min · jiezi

laradock-使用-phpworker-配置-supervisor

导语因为项目使用了队列,所以想着用 supervisor 来守护进程。开始在 workspace 中没有找到,准备自己安装了。后来一查才发现是自己大意了,原来是在 php-worker 中。 编辑配置文件切换到 laradocke/php-worker 目录中,Dockerfile 和 supervisord.conf 可以根据自己的需求修改,没有需求的话可以不做改动php-worker 还有关于 schedule 的配置,有需要的可以一并配置好在 supervisord.d 中有示例文件,根据示例文件新建 web-worker.conf 如下process_name=%(program_name)s_%(process_num)02dcommand=php /var/www/you_project_path/artisan queue:work --sleep=3 --tries=3 --daemonautostart=trueautorestart=truenumprocs=2user=laradockredirect_stderr=true启动容器在 laradock 目录下 docker-compose build --no-cache php-worker启动 docker-compose up -d php-worker结语很简单的几步就搞定了,这就是 laradock 的好处之一,当然这一切都是建立在 docker 之上。

April 24, 2019 · 1 min · jiezi

homestead-安装swoole扩展

执行以下命令 vagrant sshsudo pecl channel-update pecl.php.netsudo pecl install swoole会看到如下提示意思就是扩展已经安装好了,需要在php.ini里面进行配置。输入命令 php -i|grep php.ini会显示php.ini 所在的目录vim /目录/php.ini, 在其中加入extension=swoole.so 重启php-fpm sudo service php7.3-fpm reload检查扩展是否安装完毕 php -m|grep swoole

April 23, 2019 · 1 min · jiezi

十个推荐使用的 Laravel 的辅助函数

文章转自:https://learnku.com/laravel/t... Laravel 包含各种全局辅助函数。 laravel 中包含大量辅助函数,您可以使用它们来简化开发工作流程。 在这里,我将编写10个最好的 laravel 帮助函数,用于使我的开发更容易。 您必须考虑在必要时使用它们。 您还可以查看所有的官方文档 laravel helper functions. array_dot()array_dot() array_dot() 辅助函数允许你将多维数组转换为使用点符号的一维数组。 $array = [ 'user' => ['username' => 'something'], 'app' => ['creator' => ['name' => 'someone'], 'created' => 'today']];$dot_array = array_dot($array);// [user.username] => something, [app.creator.name] => someone, [app.created] => todayarray_get()array_get() 函数使用点符号从多维数组中检索值。 $array = [ 'user' => ['username' => 'something'], 'app' => ['creator' => ['name' => 'someone'], 'created' => 'today']];$name = array_get($array, 'app.creator.name');// someone如果key不存在,array_get() 函数还接受可选的第三个参数作为默认值。 ...

April 22, 2019 · 1 min · jiezi

Laravel10个有用的用法

1. 在find方法中指定属性User::find(1, ['name', 'email']);User::findOrFail(1, ['name', 'email']);2. Clone一个Model用replicate方法可以克隆一个Model $user = User::find(1);$newUser = $user->replicate();$newUser->save();3. 判断两个Model是否相同检查两个Model的ID是否相同用is方法 $user = User::find(1);$sameUser = User::find(1);$diffUser = User::find(2);$user->is($sameUser); // true$user->is($diffUser); // false;4. 重新加载一个Model$user = User::find(1);$user->name; // 'Peter'// 如果 name 更新过,比如由 peter 更新为 John$user->refresh();$user->name; // John5. 加载新的Model$user = App\User::first();$user->name; // John//$updatedUser = $user->fresh(); $updatedUser->name; // Peter$user->name; // John6. 更新带关联的Model在更新关联的时候,使用push方法可以更新所有Model class User extends Model{ public function phone() { return $this->hasOne('App\Phone'); }}$user = User::first();$user->name = "Peter";$user->phone->number = '1234567890';$user->save(); // 只更新 User Model$user->push(); // 更新 User 和 Phone Model7. 自定义软删除字段Laravel默认使用deleted_at作为软删除字段,我们通过以下方式将deleted_at改成is_deleted ...

April 21, 2019 · 1 min · jiezi