🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# :-: Lravel学习笔记 为了方便以后移植,就全部写在一个页面上 基于官方文档和项目中实际使用的,绝大部分都是我项目中实际用到的 主要是自己记录,如果你不小心看到了,可以去我个人博客 www.shuxiaoyuan.com 或者邮箱联系我: sxy@shuxiaoyuan.com ***** [TOC] ## 一些简单的配置 Nginx的URL美化 ``` location / { try\_files $uri $uri/ /index.php?$query\_string; } ``` 开启或关闭维护模式 ``` //开启维护模式,关闭站点 php artisan down //message:自定义消息,retry:设置 HTTP 请求头的 RetryAfter: php artisan down --message="维护数据库" --retry=60 //关闭维护模式,开启站点 php artisan up ``` ## 路由 写在web.php里面的路由有CSRF保护,可以在 app/Http/Middleware/VerifyCsrfToken.php中排除掉 ``` protected $except = [ '/wx/api/sign/msg_push','openapi/*' ]; ``` ~~~ //路由方法 Route::get($uri, $callback); Route::post($uri, $callback); Route::put($uri, $callback); Route::patch($uri, $callback); Route::delete($uri, $callback); Route::options($uri, $callback); Route::match(['get','post'],'$url',$callback); //参数必选和可选,相当于给函数传递参数 Route::any('test/{id}', 'TestController@index'); 在控制器中:public function(Request $request, $id){} Route::any('test/{id?}', 'TestController@index'); //路由到页面 Route::any('/', function () { return view('welcome'); }); //路由到控制器,命名空间为 App\Http\Controllers Route::any('test', 'TestController@index'); // 路由到控制器,带命名空间的 Route::any('/wx/api/sign/msg_push', '\App\Http\Controllers\Wx\BaseController@signMsgPush'); //命名空间路由+前缀 Route::namespace('Home')->prefix('home')->group(function () { Route::get('/index', 'IndexController@index'); }); //命名空间路由+前缀+中间件,多个中间件按照先后顺序执行 Route::namespace('Wx')->prefix('wx')->middleware(['check.openid'])->group(function () { Route::get('/index/{id}', 'IndexController@index');//首页 }); //可以多层嵌套,执行顺序是:outer 、 inner 、 array1 、 array2 //Route::group(['middleware' => 'outer'], function () { // Route::group(['middleware' => 'inner'], function () { // Route::group(['middleware' => ['array1', 'array2', 'auth:api']], function () { // Route::get('test', function () { // return; // }); // }); // }); //}); ~~~ 部署使用路由缓存 ` php artisan route:cache` 清除路由缓存:` php artisan route:clear` ## 中间件 在中间件总处理session的问题,有坑,记录一二 一、中间件会先走类的构造方法(可能跟依赖注入有关,没有详细的了解) 二、请详细了解laravel一次请求的完整生命周期,如果需要在中间件中保存session在控制器中用,其实大部分情况是失败的,第二次访问的时候就好了,因为他是一次请求结束后(return,exit等)才会写入session,项目中主要是写了一个微信授权的中间件,详细可以看我的博客这篇文章:https://www.shuxiaoyuan.com/index.php/Home/Index/article/aid/108 ## 控制器 控制器依赖注入:构造函数注入、方法注入 一、构造函数注入 ~~~ private $token = ''; private $wx_name = ''; private $wx_isEncryption = ''; public function __construct() { $this->token = env('WX_TOKEN'); $this->wx_name = env('WX_NAME'); $this->wx_isEncryption = env('WX_TEST'); } ~~~ ## HTTP请求和响应(参数输入输出,文件上传下载,表单验证) ## 视图,不需要太多 ## session 默认使用文件保持session,如需修改,除了在env文件中修改外,还需要在配置文件中做修改 使用database保存session:需要创建表,执行下面两条语句 `php artisan session:table` ` php artisan migrate` 使用redis保存session:在config/database.php 中为 Redis 配置Session连接 ~~~ 'redis' => [ 'client' => 'predis', 'default' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 0, ], 'session' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => 6, ], ], ~~~ ## 日志文件记录 按天保存日志文件:daily ~~~ 'log' => env('APP_LOG', 'daily'), 'log_max_files' => 30,//最大日志文件数 'log_level' => env('APP_LOG_LEVEL', 'debug'), ~~~ ## 原生和DB操作数据库 原生查询:直接写原生SQL就行 `$results = DB::select('select * from users where id = ?', [1]);` DB查询 ``` //查询一条数据 EventStock::where('event_id', $event_id) ->where('shop_code', $store_id) ->where('number','>','100') ->select('stock')->first(); //查询多条数据 $users = DB::table('users')->where('start', '1')->get(); //根据主键取值 $user = DB::table('users')->find(1); $user = DB::table('users')->find(['1','2','4']); //聚合查询 $users = DB::table('users')->count(); $price = DB::table('orders')->max('price'); ``` DB新增 ``` DB::table('users')->insert([ ['email' => 'taylor@example.com', 'votes' => 0], ['email' => 'dayle@example.com', 'votes' => 0] ]); //获取自增ID $id = DB::table('users')->insertGetId( ['email' => 'john@example.com', 'votes' => 0] ); ``` DB更新 ``` DB::table('users')->where('id', 1)->update(['votes' => 1]); DB::table('users')->increment('votes'); DB::table('users')->increment('votes', 5); DB::table('users')->decrement('votes'); DB::table('users')->decrement('votes', 5); ``` DB删除 ``` DB::table('users')->delete(); DB::table('users')->where('votes', '>', 100)->delete(); //清空表数据并重置自增ID DB::table('users')->truncate(); ``` ## 数据库迁移 生成迁移文件 `php artisan make:migration create_users_table` 运行迁移 `php artisan migrate` 回滚迁移 回滚最后一次:`php artisan migrate:rollback` 回滚最后5次:`php artisan migrate:rollback --step=5` 回滚所有:`php artisan migrate:reset` 删除所有表并重新迁移:` php artisan migrate:fresh` 具体怎么创建表,看文档吧 ## 数据库填充 生成填充文件:这个里面随便写,循环插入,批量插入,随便玩,复杂点的用模型工厂来快速生成大量数据 `php artisan make:seeder UsersTableSeeder` 运行填充文件填充数据 `php artisan db:seed` `php artisan db:seed --class=UsersTableSeeder` 也可以运行其他填充类 `$this->call(UsersTableSeeder::class);` 可能需要重新生成Composer自动加载器 `composer dump-autoload` ## 采用模型工厂来批量写入假数据 创建一个模型工厂,并指定数据库模型: ` php artisan make:factory PostFactory --model=Post` 编写需要写入的字段数据: 备注:关于更多的Faker数据,请参考以下网址 https://github.com/fzaninotto/Faker https://packagist.org/packages/fzaninotto/faker ~~~ <?php use Faker\Generator as Faker; $factory->define(App\Models\RushBuyEventRecord::class, function (Faker $faker) { $idCard = new \App\Common\IdCard(); return [ 'unionid' => $faker->unique()->uuid, 'event_id' => mt_rand(1,3), 'size' => $faker->numberBetween(30,45), 'city' => $faker->city, 'name' => $faker->firstNameMale,//男性名字 'id_card_number' => $idCard->getIDCard(), 'reserve_time' => $faker->date("Y-m-d H:i:s","2019-07-01"), 'type' => mt_rand(1,2), 'reserve_ip' => $faker->ipv4.', '.$faker->ipv4, 'draw_ip' => $faker->ipv4.', '.$faker->ipv4, 'milli_draw_time' => microtime(true), 'mobile' => $faker->phoneNumber, ]; }); ~~~ ## Eloquent ORM操作数据库 Eloquent 模型可以触发事件,允许你在模型生命周期中的多个时间点调用如下这些方法: retrieved, creating, created, updating, updated, saving, saved, deleting, deleted, restoring, restored。事件允许你在一个指定模型类每次保存或更新的时候执行代码 ### when用法 ~~~ return BuyEventSuccessfuls::where('store_id', $store_id) ->when($event_id, function ($query) use ($event_id) { return $query->where('event_id', $event_id); }, function ($query) use ($eventIds) { return $query->whereIn('event_id', $eventIds); })->select('id', 'name', 'mobile', 'status') ->where('status', '=', "$status") ->paginate(20) ->toArray(); ~~~ ### 事务 通过use 来给闭包传参 ~~~ $a = DB::transaction(function () use ($request,$id) { $data = $request->only('name', 'serial_number', 'addre', 'lng', 'lat', 'channel', 'type', 'area', 'city'); $consume_account = $request->json('accounts'); foreach ($consume_account as $k => $v) { $consume_account[$k]['store_id'] = $data['serial_number']; $consume_account[$k]['password'] = password_hash($consume_account[$k]['password'], PASSWORD_BCRYPT); $consume_account[$k]['cookie_info'] = $v['username'] . ':' . $data['serial_number'] . ':' . time(); $consume_account[$k]['state'] = 0; $consume_account[$k]['created_at'] = date('Y-m-d H:i:s'); $consume_account[$k]['updated_at'] = date('Y-m-d H:i:s'); } try { Store::where('id', $id)->update($data); DB::table('consume_login')->insert($consume_account); DB::commit(); return true; } catch (\Exception $exception) { DB::rollBack(); return false; } }); ~~~ ### 在使用with的时候,默认是获取所有字段,可以采用如下方式 指定select字段,注意,一定要有关联id,如果去掉,会报错或者取不到数据 ~~~ public function getevent() { return $this->hasOne('App\Models\RushBuyEvents', 'id', 'event_id') ->select('id','event_title', 'consume_start', 'consume_end'); } public static function getEventInfoByStoreID($store_id) { $data = RushBuyEventStores::where('store_id', $store_id) ->select('event_id','store_id') ->with('getevent') ->get() ->toArray(); dd($data); exit; } ~~~ 打印数据为: ~~~ array:5 [ 0 => array:3 [ "event_id" => 90 "store_id" => "PN0000" "getevent" => array:4 [ "id" => 90 "event_title" => "HENDER SCHEME (F36048)" "consume_start" => "2019-06-25 10:00:00" "consume_end" => "2019-06-26 18:00:00" ] ] 1 => array:3 [ "event_id" => 91 "store_id" => "PN0000" "getevent" => array:4 [ "id" => 91 "event_title" => "HENDER SCHEME (F36147)" "consume_start" => "2019-06-26 10:00:00" "consume_end" => "2019-06-26 18:00:00" ] ] ] ~~~ ## 安全操作(加密,哈希,认证等) ## 缓存(redis) 可以用Redis的管道 发布,订阅 ## 事件 ## 通知,广播,队列,任务调度 * 任务调度:首先需要在Linux上面创建一条计划任务,该计划任务是每分钟调用laravel的命令 Linux上的命令`crontab -e ` 输入以下内容: ` * * * * * php /项目目录/artisan schedule:run >> /dev/null 2>&1` 下面就简单了,在Console/Commands目录下创建任务文件 ~~~ app\Console\Commands\Test.php <?php namespace App\Console\Commands; use Illuminate\Console\Command; class ImgTotext extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'img_to_text';//命令名称 /** * The console command description. * * @var string */ protected $description = '图片识别';//命名描述 /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { //这里写你要干嘛,随便写拉。 } } 然后在 app\Console\Kernel.php文件中填写如下内容,执行时间看具体文档 protected function schedule(Schedule $schedule) { $schedule->command('img_to_text')->everyMinute(); $schedule->command('send_kf_msg')->everyFiveMinutes(); } 更高级的应用(任务重叠,任务输出,任务钩子等),看文档,我没有试 ~~~ ## 邮件 ## 测试