Laravel常用代码合集

用Laravel也有不短的时间了,也用过不少版本了,以下代码是在日常项目中收集,作为笔记,也分享出来,希望对你有点用处。
注:版本没标注,若有不兼容的问题,微调即可。

验证

不太习惯单独弄个Request验证类,比较习惯下面的写法:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

    $inputData = $request->only(['name', 'address', 'mobile', 'draw_id']);
    $messages = [
        'required'=>':attribute为必填项',
         'int'=>':attribute参数类型错误',
         'max'=>':attribute长度不得超过 :size',
    ];
    $validator = Validator::make($inputData, [
        'draw_id' => 'required|int',
        'name' => 'required',
        'mobile' => 'required',
        'address' => 'required',
    ], $messages,[
        'name'=>'收货人姓名',
        'mobile'=>'手机号码',
        'address'=>'收货地址',
    ]);

    if ($validator->fails()) {
        return self::response([], current($validator->errors()->all()), 2);
    }

自定义验证

比如常用的手机号验证:

php artisan make:rule Mobile

然后改一下:


    /**
     * Mobile主要代码
     * 验证是否通过
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        //
        return preg_match('/^1\d{10}$/', $value);
    }

    /**
     * 错误信息
     *
     * @return string
     */
    public function message()
    {
        return '手机号格式不正确';
    }

然后这么用起来:

$columns = [
    'college' => 'required|max:32',
    'mobile' => ['required', new Mobile()],
    'qq' => 'required',
];

ORM

关联查询

  • 一对一

    // Model定义,关联外键
    class User extends Model
    {
      ...
    
      public function userIntegral()
      {
          return $this->hasOne('App\Models\UserIntegral', 'user_id', 'id');
      }
    }
    // 使用with查询
    (new User())->with('userIntegral')->orderBy('id', 'desc')->paginate($limit);
  • 一对多

    //Model
    namespace App\Models;
    use Illuminate\Database\Eloquent\Model;
    class Hotel extends Model
    {
      public function orders()
      {
          return $this->hasMany('App\Models\Order');
      }
    }
    //使用,比如查询某个Hotel下status=30的Order
    $hotel = Hotel::with(['orders' => function ($query) {
          $query->where('status', 30);
      }])->find(4);

统一异常处理

这个可以参见之前的文章Laravel 统一错误处理为 JSON

队列

失败队列入库

  • 生成表
    生成failed_jobs表

    php artisan queue:failed-table
    php artisan migrate
  • 单独处理

可以在Job中单独处理失败,Job失败也会写入上面生成的failed_jobs表

/**
* 任务失败的处理过程
*
* @param  Exception  $exception
* [@return](https://learnku.com/users/31554) void
*/
public function failed(Exception $exception)
{
    // 处理
}

重试队列

有时候代码有漏洞可能会有队列执行失败的状况,这时候我们就需要重试。

  • 查看所有失败
    php artisan queue:failed
  • 重试所有失败
    php artisan queue:retry all
  • 重试单个失败
    php artisan queue:retry 13
  • 清空失败(重要的队列数据万不可这么操作)
    php artisan queue:flush

另外,手动去操作确实不太方便,你可以设置个cron,定时重试所有失败,但务必要注意消息提醒,以免队列一直重试一直失败,往复运行,影响了正常的队列性能。

其他常用代码

文件上传OSS

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Controller;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use OSS\OssClient;
use OSS\Core\OssException;

class UploadController extends Controller
{
    public function index(Request $request)
    {
        $file = $request->file('file');
        if ($file->isValid()) {
            $ext = $file->getClientOriginalExtension();
            $realPath = $file->getRealPath();
            $filepath = config('app.env').'/' . md5(uniqid('', true));

            $result = $this->uploadOss($realPath, $filepath.".".$ext);

            if ($result['code']) {
                return response(['code' => 2, 'msg' => $result['msg']]);
            } else {
                return response(['code' => 0, 'msg' => '上传成功', 'data' => [
                    'filepath' => $result['data']['url'],
                    'data' => $request->all()
                ]]);
            }
        }
    }

    /**
     * 上传oss
     * @param $filePath  当前路径
     * @param $object   预定义文件名,可含文件夹
     * [@return](https://learnku.com/users/31554) array
     */
    public function uploadOss($filePath, $object)
    {
        $accessKeyId = config('filesystems.disks')[config('filesystems.default')]['access_key'];
        $accessKeySecret = config('filesystems.disks')[config('filesystems.default')]['secret_key'];
        $endpoint = config('filesystems.disks')[config('filesystems.default')]['endpoint'];
        $bucket= config('filesystems.disks')[config('filesystems.default')]['bucket'];
        $url = config('filesystems.disks')[config('filesystems.default')]['host'];

        try{
            $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
            $ossClient->uploadFile($bucket, $object, $filePath);
            return [
                'code' => 0,
                'data' => [
                    'url' => $url.'/'.$object
                ]
            ];
        } catch(OssException $e) {
            return [
                'code' => 1,
                'msg' => $e->getMessage()
            ];
        }
    }
}


// -------
// 配置
'oss' => [
  'driver' => 'oss',
  'root' => '',
  'access_key' => env('OSS_ACCESS_KEY'),
  'secret_key' => env('OSS_SECRET_KEY'),
  'endpoint' => env('OSS_ENDPOINT'), // 使用 ssl 这里设置如: https://oss-cn-beijing.aliyuncs.com
  'bucket' => env('OSS_BUCKET'),
  'isCName' => env('OSS_IS_CNAME', false), // 如果 isCname 为 false,endpoint 应配置 oss 提供的域名如:`oss-cn-beijing.aliyuncs.com`,否则为自定义域名,,cname 或 cdn 请自行到阿里 oss 后台配置并绑定 bucket
  'host' => env('OSS_HOST', '')
],

json输出

protected static $code = 0;
protected static $msg = 'ok';

public function response($data = [], $msg = '', $code = 0)
{
    if (is_null($data)) {
        $data = new \stdClass();
    }
    return response()->json([
        'code' => $code? $code : self::$code,
        'msg' => $msg? $msg : self::$msg,
        'data' => $data,
    ], 200);
}

进程锁

  • 普通版本

    // $autoDel字段删除,$ttl 过期时间,秒
    public function  processLock($key, $autoDel = true, $ttl = 60)
    {
      $key = 'processLock:'.$key;
      // 不同版本或redis扩展,会有略微不同,自行调整下代码即可
      if (Redis::Command('set', [$key, 1, 'EX', $ttl, 'NX'])) {
          if ($autoDel) {
              register_shutdown_function(function () use ($key) {
                  Redis::del($key);
              });
          }
    
          return true;
      }
      return false;
    }
  • lua版本

    public function getScript()
    {
        return <<<LUA
        local ret = redis.call("setnx", KEYS[1], ARGV[1])
        if ret == 1 then
            return redis.call("expire", KEYS[1], ARGV[2])
        else
            return 0
        end
LUA;
    }


    public function processLock($key, $autoDel = true, $ttl = 60)
    {
        if (Redis::eval($this->getScript(), 1, $key, 1, $ttl)) {
            if ($autoDel) {
                register_shutdown_function(function () use ($key) {
                    Redis::del($key);
                });
            }

            return true;
        }
        return false;
    }

说明:Redis::eval行第一个1表示key的数量,是为了区分KEYS和ARGV。

JWT

Laravel 配合 jwt 使用

系统通知到钉钉

我们可以使用队列,把一些重要的通知投到钉钉,主要代码如下:

<?php

namespace App\Jobs;

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\Log;
use GuzzleHttp\Client;


class SystemNotify implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private $title;

    private $content;

    private $type;

    private $robot;

    const DD_URL = 'https://oapi.dingtalk.com';

    /**
     * Create a new job instance.
     *
     * @param $title
     * @param string $content
     * @param string $type text, markdown
     * @param int $robot
     */
    public function __construct($title, $content = '', $type = 'markdown', $robot = 1)
    {
        // 单独使用SystemNotify队列
        $this->queue = 'SystemNotify';
        $this->title = $title;
        $this->content = $content;
        $this->type = $type;
        $this->robot = $robot;

    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // 可以不使用关键字,建议钉钉机器人使用IP段设置,更为安全
        switch ($this->type){
            case 'markdown':
                $params = [
                    'msgtype' => $this->type,
                    $this->type => [
                        'title' => $this->title.'[关键字]',
                        'text' => $this->content
                    ]
                ];
                break;
            default:
                $params = [
                    'msgtype' => $this->type,
                    $this->type => [
                        'content' => $this->content.'[关键字]',
                    ]
                ];
                break;

        }
        $params = json_encode($params, JSON_UNESCAPED_UNICODE);


        $uri = self::URL_MAPPING[$this->robot];
        $this->getClient()->request('POST', $uri, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8'
            ],
            'body' => $params
        ]);
    }

    // 对应不同的钉钉群通知,修改access_token参数即可
    const URL_MAPPING = [
        1 => '/robot/send?access_token=@1',
        2 => '/robot/send?access_token=@2'
    ];

    public function getClient()
    {
        return new Client([
            'base_uri' => 'https://oapi.dingtalk.com',
            'timeout'  => 30,
            'verify' => false
        ]);
    }
}

说明:通知内容可以自定义,添加智能机器人操作比较简单就不赘述了

后台操作日志

利用 Laravel 中间件给后台加个操作日志

Excel

Laravel6 配合 Maatwebsite\Excel 实现 Excel 导入

Laravel6 配合 Maatwebsite\Excel 实现 Excel 导出

陆续补充中…

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 4年前 自动加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 4

进程锁,那部分 用原子锁不香吗

4年前 评论
已下线 (楼主) 4年前
北冥

我验证一般喜欢这样:

$this->validate($request, [
        'supplier' => 'required',
        'prt_id' => 'required',
        'number' => 'required|numeric|integer|min:0',
        'dpt_id' => 'required',
    ],[
        'prt_id.required' => trans('messages.select_product'),
    ],[
        'supplier' => trans('labels.supplier'),
        'number' => trans('labels.number'),
        'dpt_id' => trans('labels.application_department'),
    ]
);
4年前 评论
JerryBool 4年前
已下线 (楼主) 4年前
sunny123456 4年前

大佬我问个问题:一对多哪里

$category = Category::with(['goods' => function ($query) {
      $query->where('is_sale', true);
  }])->find($categoryId);

goods是引入模型我知道 Category 要怎么引入啊

4年前 评论
已下线 (楼主) 4年前
it_cwc (作者) 4年前
已下线 (楼主) 4年前
xuri

推荐一个功能丰富、兼容性好、高性能的 Excel 文档基础库:github.com/xuri/excelize

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!