2019年12月
2019-12-2 周一
Laravel 判断请求方法
if ('DELETE' === strtoupper(Request::method())) { // DO SOMETHING }
Laravel 异常处理
假设有一个 Illuminate\Database\Eloquent\ModelNotFoundException
:
$post = Post::findOrFail($id);
在 App\Exceptions\Handler.php
中捕获:
public function render($request, Exception $e) { if ($e instanceof ModelNotFoundException) { // 请求方法是删除 if ('DELETE' === strtoupper(Request::method())) { return Response::json([ 'success' => true ]); } if ($request->ajax() || $request->wantsJson()) { return response()->json([ 'message' => '没有找到' ], 404); } else { return response()->view('errors.404', [ ], 404); } } return parent::render($request, $e); }
记录异常:
protected $dontReport = [ ModelNotFoundException::class, ];
2019-12-3 周二
处理 Dingo
的异常:
使用了 Dingo
后就不能用上面的方法去处理所有的异常了,Dingo
接口需要额外处理
方法在 app/Providers/AppServiceProvider.php
中
/** * Bootstrap any application services. * * @return void */ public function boot() { // }
在 boot()
方法中添加:
public function boot(){ app('Dingo\Api\Exception\Handler')->register(function (Exception $exception) { // 处理异常 if ($exception instanceof ModelNotFoundException) { if ('DELETE' === strtoupper(Request::method())) { return Response::json([ 'success' => true ]); } if ($request->ajax() || $request->wantsJson()) { return response()->json([ 'message' => '没有找到' ], 404); } else { return response()->view('errors.404', [ ], 404); } } }); }
参考:laravel接管Dingo-api和默认的错误处理(编写方式略有不同)
2019-12-4 周三
悲观锁:
DB::beginTransaction(); try { $enterprise = Enterprise::where('id', '=', $id) ->lockForUpdate() ->first(); // DO SOMETHING DB::commit(); } catch (Exception $exception) { DB::rollBack(); throw $exception; }
sharedLock
对应的是 LOCK IN SHARE MODE
lockForUpdate
对应的是 FOR UPDATE
sharedLock
与 lockForUpdate
相同的地方是,都能避免同一行数据被其他 transaction
进行 update
不同的地方是:
sharedLock
不会阻止其他 transaction
读取同一行
lockForUpdate
会阻止其他 transaction
读取同一行 (需要特别注意的是:普通的非锁定读取读取依然可以读取到该行,只有 sharedLock
和 lockForUpdate
的读取会被阻止。)
2019-12-5 周四
当无法识别存在的文件时,执行命令:
composer dump-autoload --optimize
2019-12-6 周五
MySQL 优化
在 my.ini
文件中修改以下参数
max_connections=512 tmp_table_size=128M thread_cache_size=128 myisam_sort_buffer_size=256M key_buffer_size=1024M read_buffer_size=32M read_rnd_buffer_size=32M innodb_log_buffer_size=32M innodb_buffer_pool_size=1G innodb_log_file_size=512M back_log=200 join_buffer_size=32M sort_buffer_size=32M
2019-12-7 周六
递归:recursive call
2019-12-9 周一
Seeder 报错:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`TEST`.`role_has_permissions`, CONSTRA INT `role_has_permissions_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE) (SQL: insert into `role_has_permissions` (`permission_id`, `role_id`) values (1, 1))
解决方法:
DB::statement('SET FOREIGN_KEY_CHECKS = 0'); // 禁用外键约束 DB::table('model_has_roles')->truncate(); DB::table('model_has_roles')->insert(array ( array ( 'role_id' => 1, 'model_type' => 'App\\User', 'model_id' => 934, ), )); DB::statement('SET FOREIGN_KEY_CHECKS = 1'); // 启用外键约束
在执行 Seeder的时候将外键约束先禁用,执行完后再启用即可
2019-12-10 周二
正则表达式
匹配带有 string
字符的行:
^(.*)string(.*)\n
匹配空行:
^\n
PHPStorm
替换快捷键:Ctrl
+ R
2019-12-11 周三
判断字段是否存在:
Schema::table('users', function (Blueprint $table) { if ($table->hasColumn('email')) { // 用户表里存在 Email } });
这样写也可以:
if (Schema::hasColumn('users', 'email')) { // DO SOMETHING } if (Schema::hasColumns('users', ['email', 'phone'])) { // DO SOMETHING }
2019-12-12 周四
微信小程序订阅消息
弹出提示让用户接受消息订阅:
wx.requestSubscribeMessage({ tmplIds: [ 'TGZzqLAviHZjCKszjaC80qqWnki50rUWuiZnGGCUYRw', 'Xwc_GbmFjrlM1recJBJgN7pY5jKHreUZTc51ATEGZ6I', '75-X17FB815ChZUE50iI0s6rX-5nrvptPZV6MsKtzbY' ], success(res) { console.log('已授权接收订阅消息') } })
实现的 Job
方法:
<?php namespace App\Jobs; use App\Services\AppletCodeService; use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\Psr7\Request; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\App; class SendSubscribeMsg implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $appID; protected $appSecret; protected $accessToken; protected $url; protected $data; protected $openID; protected $templateID; /** * Create a new job instance. * * @param $data array 数据 * @param $openID string 微信ID * @param $templateID string 消息模板ID * @param $url string 跳转地址 */ public function __construct($data, $openID, $templateID, $url) { $this->data = $data; $this->openID = $openID; $this->templateID = $templateID; $this->url = $url; $this->appID = config('ebooking-app.AppID'); $this->appSecret = config('ebooking-app.AppSecret'); // 本地环境时使用测试用的 AppID 和 AppSecret if (App::environment('local')) { $this->appID = config('ebooking-app.AppID-test'); $this->appSecret = config('ebooking-app.AppSecret-test'); } $this->accessToken = app(AppletCodeService::class)->getToken($this->appID, $this->appSecret); } /** * Execute the job. * * @return void * @throws GuzzleException */ public function handle() { $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $this->accessToken; $params['touser'] = $this->openID; $params['template_id'] = $this->templateID; $params['page'] = $this->url; $params['data'] = $this->data; $client = new Client(); $client->send(new Request('POST', $url, [], json_encode($params))); } }
发送:
dispath(new SandSubscribeMsg( [ 'thing1' => ['value' => '每日早起'], 'time3' => ['value' => '2099/12/30 20:00'], 'name4' => ['value' => '小明'], 'thing2' => ['value' => '有虫吃'], ], // 数据 'AAAAAAAAAA', // OPEN_ID 'BBBBBBBBBB', // 模板ID 'CCCCCCCCCC' // URL 跳转链接 ));
2019-12-13 周五
PHP 获取变量类型:
$a = 56; echo gettype($a); // integer settype($a, 'double'); echo gettype($a); // double
2019-12-16 周一
显示 DNS
记录:
ipconfig /displaydns
立即刷新 DNS
记录:
ipconfig /flushdns
2019-12-17 周二
单位 分
转换为单位 元
:
round($payAmount / 100, 2)
2019-12-18 周三
确定当前应用程序所处的环境
$environment = App::environment(); if (App::environment('local')) { // 当前环境是 local } if (App::environment(['local', 'staging'])) { // 当前的环境是 local 或 staging }
直接访问配置文件的值:
$value = config('app.timezone');
如果需要在运行的时候设置配置值:
config(['app.timezone' => 'China/Jiangsu']);
2019-12-19 周四
Laravel 维护模式
# 启用维护模式 php artisan down
可选参数 message
:记录自定义消息,retry
:返回 HTTP 头部消息让客户端 XX 秒之后再重试,allow
:允许特定的 IP 地址或网络访问应用程序
php artisan down --message="数据库升级中" --retry=60 --allow=127.0.0.1 --allow=192.168.0.0/16
关闭维护模式:
php artisan up
当应用程序处于维护模式时,不会处理 队列任务。而这些任务会在应用程序退出维护模式后再继续处理
维护模式会导致应用程序有数秒的停机(不响应)时间,因此可以考虑使用像 Envoyer 这样的替代方案,以便与 Laravel 完成零停机时间部署
2019-12-20 周五
消息队列延迟发送:
// 在构造函数中加上这个即可 $this->delay = Carbon::tomorrow()->addHour(24);
2019-12-21 周六
file_get_contents
异常
$url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appID}&secret={$appSecret}&js_code={$jsCode}&grant_type=authorization_code"; $html = file_get_contents($url);
错误不大,URL
的拼接不能换行,不能因为 IDE 标黄就多此一举给它换个行
2019-12-23 周一
Python 载入 Json 数据
json.loads(r.get(content))
需要注意,如果里面为空会产生异常
所以需要判断是否存在:
if (r.exists(content))
2019-12-24 周二
判断数组键值是否存在:
if (!array_key_exists('name', $output)) { return response()->error(-1, ERROR::DATA_ERROR); }
2019-12-25 周三
通过微信小程序的 JSCode
获取 OpenID
:
$url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appID}&secret={$appSecret}&js_code={$jsCode}&grant_type=authorization_code"; $html = file_get_contents($url); $output = json_decode($html, true); if (!array_key_exists('openid', $output)) { Log::warning('获取用户的微信OpenID异常' . $jsCode); return response()->error(); } $openID = $output['openid'];
2019-12-26 周四
Python 两个列表的差集
# 在B中但不在A中 result = list(set(listB).difference(set(listA)))
2019-12-27 周五
相对标准一点的单元测试
<?php namespace Tests\Feature\Api; use App\Http\Middleware\ApiAuth; use App\Models\Tools\ResponseJson; use Tests\TestCase; /** * Class ExampleTest * * @coversDefaultClass \App\Http\Controllers\Api\Info\InfoController * @package Tests\Api */ class InfoControllerTest extends TestCase { /** * 测试 Info * * @covers ::index * @return void */ public function testIndex() { $response = $this->withHeader('token', ApiAuth::API_KEY) ->get('/info'); $response->assertStatus(200) ->assertJson([ 'code' => ResponseJson::RESPONSE_CODE, 'message' => ResponseJson::RESPONSE_MESSAGE, ]); } }
其中,请求还可以写成这样:
$response = $this->withHeaders([ 'X-Header' => 'Value', ])->json('POST', '/user', ['name' => 'Tabll']);
2019-12-30 周一
打印出测试的数据
$response->dumpHeaders(); $response->dump();
会得到这样的输出:
2019-12-31 周二
Laravel 数据模型的自定义
// 自定义表明 protected $table = 'my_flights';
// 自定义主键 protected $primaryKey = 'flight_id';
// 定义主键是否会自增 public $incrementing = false;
// 自增ID的类型 protected $keyType = 'string';
// 忽略时间戳 public $timestamps = false; // 自定义时间戳名 const CREATED_AT = 'creation_date'; const UPDATED_AT = 'last_update';
// 指定的数据库连接 protected $connection = 'connection-name';
// 定义默认值 protected $attributes = [ 'delayed' => false, ];