让php开发更优雅-Laravel篇

前言


随着开发经验的增加,也伴随团队开发的积累,规范开发显得越来越重要,本文给大家提供一些laravel开发的进阶思路和经验,让大家开发更加统一规范,代码看起来更加优雅。

1.更多使用第三方库。团队开发的时候,各个人的开发经验和思考方式不同,也有一些思维局限性,可以多多使用第三方库,统一代码开发规范。

2.抛弃传统MVC模式,在结构上分出更新的结构分层,进行代码解耦。一般分为下面几层:

  • 数据验证层(Request):负责验证请求参数,单独创建一个验证请求器,避免验证逻辑放在控制器中验证,例如:

    Laravel框架使用FormRequest Laravel中使用FormRequest进行表单验证及对验证异常进行自定义处理_51CTO博客_laravel 表单验证

    TP框架使用FormRequest thinkphp6 FormRequest,laravel 表单验证_think\request和laravel-CSDN博客

  • 控制器层(Controller):负责接收参数、验证参数、调用各个模块的服务层(可以用事务包裹,用到其他服务的可以注入多个服务)、返回响应、返回视图等

  • 服务层(Service):负责具体的业务逻辑实现,将原本控制器的负责流程按模块拆分为一个个小的服务,方便给控制器层组合调用,一般不要跨模块调用服务,服务中可以调用本模块的仓库层方法

  • 仓库层(Repository):调用模型层封装一些负责的查询,方便服务层调用,一般负责只查询本模块的内容

  • 模型层(Model):只包含默认的表属性(表名、字段等)和联表关系

  • (更多层级)

环境搭建


为了不重复造轮子和方便命令行创建文件,本文直接用laravel自带的FormRequest和第三方phpno1-architecture这两个包进行开发示例,这两个库的具体使用可以参考下面几篇文章:

https://learnku.com/articles/9763/open-source-wheel-laravel-project-architecture-extension-package

Laravel中使用FormRequest进行表单验证及对验证异常进行自定义处理_51CTO博客_laravel 表单验证

Laravel实现表单验证(多场景,适用于API)_laravel formrequest scenes-CSDN博客

  • 创建laravel项目

    composer create-project laravel/laravel your_project_name
    
  • 安装phpno1/architecture并发布配置

    composer require phpno1/architecture
    php artisan vendor:publish --provider "Phpno1\Architecture\Providers\ArchitectureServiceProvider"
    

    如有需要,可以修改config/architecture.php中的配置

  • 注册到服务容器

    # 在config/app.php中'providers' => [// ......App\Providers\ArchitectureServiceProvider::class,];
    
  • 如果你的laravel或php版本比较高,可能有部分辅助函数已经没有了,那么你需要添加自定义函数去代替它们,例如在app/Helpers/functions.php添加下面的辅助函数

    <?php
    /*** 自定义 ends_with 函数* @param $haystack* @param $needle* @return bool*/
    function ends_with($haystack, $needle) {return str_ends_with($haystack, $needle);
    }/*** 下划线转驼峰命名法* @param $string* @return string*/
    function camel_case($string){$parts = explode('_', $string);foreach ($parts as $index => $part) {$parts[$index] = ucfirst($part);}$camelCaseString = lcfirst(implode('', $parts));return $camelCaseString;
    }/*** 驼峰命名法转下划线命名法* @param $string* @return string*/
    function snake_case($string) {// 使用正则表达式将字符串转换为小写,并将非单词字符替换为下划线$snake = strtolower(preg_replace('/[^A-Za-z0-9-]+/', '_', $string));// 去除开头和结尾的下划线$snake = trim($snake, '_');return $snake;
    }

    然后修改文件composer.json,在autoload节点添加自定义函数文件

    "autoload": {"psr-4": {"App\\": "app/","Database\\Factories\\": "database/factories/","Database\\Seeders\\": "database/seeders/"},"files": ["app/Helpers/functions.php"]},
    

    最后执行composer dump-autoload使其生效即可

开发示例


以用户注册流程为例

统一响应

这里为了统一响应格式,直接用第三方封装的响应数据包,具体用法参考官方文档:

laravel-response: 🤖 Provide a standardized and unified response data format for Laravel and Lumen API projects. - 为 Laravel 和 Lumen API 项目提供一个规范统一的响应数据格式。 (gitee.com)

示例

Response::fail();
Response::ok();
Response::success([]);

控制器

创建控制器

php artisan make:controller UserController

控制器校验请求后调用不同 service 进行业务处理,调用 API Resource 转换资源数据返回,示例:

<?phpnamespace App\Http\Controllers;use App\Http\Requests\UserRequest;
use App\Services\SmsService;
use App\Services\UserService;
use Jiannei\Response\Laravel\Support\Facades\Response;class UserController extends Controller
{private $userId; //用户idprivate $userService; //用户业务层public function __construct(UserService $userService){$this->userService = $userService;$this->userId = 1;}/*** 获取用户信息*/public function info(){return Response::success($this->userService->getUserInfo($this->userId));}/*** 注册* * @param UserRequest $request* @param SmsService $smsService* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Resources\Json\JsonResource* @throws \Illuminate\Auth\Access\AuthorizationException* @throws \Illuminate\Validation\ValidationException*/public function register(UserRequest $request, SmsService $smsService){//参数验证$request->validate('register');//短信验证码验证if (!$smsService->check($request->mobile, 'register', $request->code)){return Response::fail('验证码错误');}try{//新增用户$this->userService->addUser($request->all());//绑定推荐人...//其他服务操作...return Response::ok();}catch (\Exception $e){return Response::fail($e->getMessage());}}
}

重点事项:

  • 将注入的Illuminate\Http\Request换成自定义的FormRequest

验证器

创建基础验证器

php artisan make:request BaseRequest

创建的验证器在app/Http/Requests/BaseRequest.php

然后修改其内容为:

<?phpnamespace App\Http\Requests;use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;/*** 基础验证器* Class AbstractRequest* @package App\Http\Requests*/
class BaseRequest extends FormRequest
{public $scenes = [];                //场景集合public $currentScene;               //当前场景public $autoValidate = false;       //是否注入之后自动验证public function authorize(){return true;}/*** 设置场景* @param $scene* @return $this*/public function scene($scene){$this->currentScene = $scene;return $this;}/*** 覆盖自动验证方法*/public function validateResolved(){if ($this->autoValidate) {$this->handleValidate();}}/*** 验证方法* @param string $scene* @throws \Illuminate\Auth\Access\AuthorizationException* @throws \Illuminate\Validation\ValidationException*/public function validate($scene = ''){if ($scene) {$this->currentScene = $scene;}$this->handleValidate();}/*** 根据场景获取规则* @return array|mixed*/public function getRules(){$rules = $this->container->call([$this, 'rules']);$newRules = [];if ($this->currentScene && isset($this->scenes[$this->currentScene])) {$sceneFields = is_array($this->scenes[$this->currentScene])? $this->scenes[$this->currentScene] : explode(',', $this->scenes[$this->currentScene]);foreach ($sceneFields as $field) {if (array_key_exists($field, $rules)) {$newRules[$field] = $rules[$field];}}return $newRules;}return $rules;}/*** 覆盖设置 自定义验证器* @param $factory* @return mixed*/public function validator($factory){return $factory->make($this->validationData(), $this->getRules(),$this->messages(), $this->attributes());}/*** 最终验证方法* @throws \Illuminate\Auth\Access\AuthorizationException* @throws \Illuminate\Validation\ValidationException*/protected function handleValidate(){$instance = $this->getValidatorInstance();if ($instance->fails()) {$this->failedValidation($instance);}$this->passedValidation();}/*** 重写验证失败返回*/protected function failedValidation(Validator $validator){$error = $validator->errors()->all();throw new HttpResponseException(response()->json(['code' => 505, 'msg' => $error['0'], 'data' => []]));}
}

接下来创建其他验证器的时候继承BaseRequest就可以了,比如创建一个UserRequest

php artisan make:request UserRequest

然后修改其内容为:

<?phpnamespace App\Http\Requests;/*** 用户模块验证*/
class UserRequest extends BaseRequest
{/*** Determine if the user is authorized to make this request.** @return bool*/public function authorize(){return true;}/*** 验证规则* Get the validation rules that apply to the request.** @return array*/public function rules(){return ['mobile' => 'required|regex:/^1[3-9]\d{9}$/','password' => 'required|min:6',];}/*** 验证字段* Get custom attributes for validator errors.** @return array*/public function attributes(){return ['mobile' => '手机号码','password' => '登录密码'];}/*** 自定义提示信息* Get custom messages for validator errors.** @return array*/public function messages(){return ['*.required' => ':attribute不能为空','*.regex' => ':attribute格式不正确','*.min' => ':attribute不能少于6位',];}/*** 定义验证场景和对应的验证字段*/public $scenes = [//注册'register' => ['mobile','password'],//登录'login' => ['mobile','password'],];
}

服务

创建服务

php artisan phpno1:service User

上面的命令会生成app/Services/UserService.php,他会自动绑定对应的仓库App\Repository\Contracts\UserRepository

<?phpnamespace App\Services;use App\Repository\Contracts\UserRepository;class UserService
{/*** @var UserRepositoryEloquent*/protected $userRepository;public function __construct(UserRepository $userRepository){$this->userRepository = $userRepository;}/*** 添加用户*/public function addUser($data){$this->userRepository->create($data);}/*** 查找用户* @param $id* @return \Illuminate\Database\Eloquent\Builder*/public function getUserInfo($id){return $this->userRepository->find($id);}
}

仓库

创建仓库

php artisan phpno1:repository User

执行命令之后会生成app/Repository/Contracts/UserRepository.phpapp/Repository/Eloquent/UserRepositoryEloquent.php;我们平时写数据库查询逻辑在UserRepositoryEloquent中写就可以了

模型

创建模型

php artisan make:model User

模型里面只保留默认的表属性和关联绑定方法即可,不处理业务

<?phpnamespace App\Models;use App\Traits\SerializeDate;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;class User extends Authenticatable
{use HasApiTokens, HasFactory, Notifiable, serializeDate;/*** The attributes that are mass assignable.** @var array<int, string>*/protected $fillable = ['name','mobile','password',];/*** The attributes that should be hidden for serialization.** @var array<int, string>*/protected $hidden = ['password','updated_at','remember_token','email_verified_at',];/*** The attributes that should be cast.** @var array<string, string>*/protected $casts = [];
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/791342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Claude-3全解析:图片问答,专业写作能力显著领先GPT-4

人工智能技术的飞速发展正在深刻改变着我们的工作和生活方式。作为一名资深的技术爱好者&#xff0c;我最近有幸体验了备受瞩目的AI助手Claude-3。这款由Anthropic公司推出的新一代智能工具展现出了非凡的实力&#xff0c;尤其在图像识别和专业写作领域的表现更是让人眼前一亮&…

JavaScript基础代码练习之冒泡排序

一、要求对一个数组进行冒泡排序&#xff0c;并将排序后的结果输出到控制台。在代码中&#xff0c;数组 arr 包含了一组数字&#xff0c;然后使用嵌套的循环来进行冒泡排序。 二、编写代码 <!DOCTYPE html> <html lang"en"><head><meta chars…

【记录】海康相机(SDK)二次开发时的错误码

海康相机&#xff08;SDK&#xff09;二次开发时的错误码 在进行海康sdk二次开发的时候&#xff0c;经常碰到各种错误&#xff0c;遂结合官方文档和广大网友的一些经验&#xff0c;把这些错误码记录一下&#xff0c;方便查找。笔者使用的SDK版本是HCNetSDKV6.1.9.4。 错误类型…

软件测试用例(2)

具体的设计方法 -- 黑盒测试 因果图 因果图是一种简化的逻辑图, 能直观地表明程序的输入条件(原因)和输出动作(结果)之间的相互关系. 因果图法是借助图形来设计测试用例的一种系统方法, 特别适用于被测试程序具有多种输入条件, 程序的输出又依赖于输入条件的各种情况. 因果图…

Flink SQL系列之:基于Flink SQL查询Topic中序列化的Debezium数据格式字段

Flink SQL系列之:基于Flink SQL查询Topic中序列化的Debezium数据格式字段 一、表结构二、查询Topic中表的数据三、反序列化字段一、表结构 CREATE TABLE IF NOT EXISTS record_rt (id decimal(20,0) COMMENT "主键",follow_entity_type <

深挖苹果Find My技术,伦茨科技ST17H6x芯片赋予产品功能

苹果发布AirTag发布以来&#xff0c;大家都更加注重物品的防丢&#xff0c;苹果的 Find My 就可以查找 iPhone、Mac、AirPods、Apple Watch&#xff0c;如今的Find My已经不单单可以查找苹果的设备&#xff0c;随着第三方设备的加入&#xff0c;将丰富Find My Network的版图。产…

fastadmin学习08-查询数据渲染到前端

index.php查询&#xff0c;这个是前台的index.php public function index() {$slideImgs Db::name("slideimg")->where("status",,normal)->limit(5)->order(sort,desc)->select();$productList Db::name("product")->where(…

python的垃圾回收

引用计数器为主&#xff0c;标记清除和分代回收为辅 1 引用计数器 在python程序运行时&#xff0c;会根据数据类型的不同找到其对应的结构体&#xff0c;根据结构体中的字段来进行创建相关的数据&#xff0c;然后将对象添加到refchain双像链表中&#xff0c;每个对象中的ob_re…

Java中生成JWT令牌

1. 在pom.xml中引入依赖 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> </dependency> 2. 使用Jwts的相关方法生成令牌 import io.jsonwebtoken.Jwts; import io.…

计算机应用 1.4网络分类

一、计算机网络的分类 1.按距离分 ①局域网&#xff1a;范围小、传输速率高、误码率低、网络延迟小。 ②广域网&#xff1a;范围广、传输速率低、误码率高、网络延迟大。 ③城域网&#xff1a;特点位于上面两者之间。 2.按拓扑结构分 ①星型网&#xff1b;②环型网&#…

【单片机家电产品学习记录--蜂鸣器】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 单片机家电产品–蜂鸣器 前言 记录学习单片机家电产品内容 已转载记录为主 一、知识点 1电子电路学习笔记&#xff08;17&#xff09;——蜂鸣器 蜂鸣器种类和原理 2疑…

虹科Pico汽车示波器 | 免拆诊断案例 | 2019款别克GL8豪华商务车前照灯水平调节故障

一、故障现象 一辆2019款别克GL8豪华商务车&#xff0c;搭载LTG发动机&#xff0c;累计行驶里程约为10.7万km。车主反映&#xff0c;车辆行驶过程中组合仪表提示前照灯水平调节故障。 二、故障诊断 接车后试车&#xff0c;起动发动机&#xff0c;组合仪表上提示“前照灯水平…

20.安全性测试与评估

每年都会涉及&#xff1b;可能会考大题&#xff1b;多记&#xff01;&#xff01;&#xff01; 典型考点&#xff1a;sql注入、xss&#xff1b; 从2个方面记&#xff1a; 1、测试对象的功能、性能&#xff1b; 2、相关设备的工作原理&#xff1b; 如防火墙&#xff0c;要了解防…

各类系统业务功能架构图整理

一、前言 很多软件系统一直经久不衰&#xff0c;主要这些系统都是一些生产工作经营不可或缺的系统。比如财务系统&#xff0c;商城系统&#xff0c;支付系统&#xff0c;供应链系统&#xff0c;人力资源管理系统&#xff0c;ERP系统等等。这些系统不管大公司还是小公司往往都需…

海外媒体宣发:如何利用6种链游媒体宣发方式推广游戏-华媒舍

在如今的游戏产业中&#xff0c;游戏宣发是非常重要的一环。而链游&#xff08;即以网游为主的游戏&#xff09;的媒体宣发方式在推广游戏中具有重要地位。本文将介绍6种链游媒体宣发方式&#xff0c;帮助游戏开发者和宣发人员更好地推广自己的游戏。 1. 游戏新闻稿 游戏新闻稿…

【科研笔记】知识星球不可选择内容爬虫

知识星球不可选择内容爬虫 1 背景2 实现3 拓展遗留问题1 背景 针对与知识星球中,电脑打开网页不可选择复制粘贴的问题,进行爬虫处理,获取网页的内容,并保存在本地 2 实现 需要下载python,和爬虫的第三方库selenium,可以查看博客中有关selenium的内容进行回顾。当前使用…

【多线程】震惊~这是我见过最详细的ReentrantLock的讲解

一.与synchronized相比ReentrantLock具有以下四个特点: 可中断&#xff1a;synchronized只能等待同步代码块执行结束&#xff0c;不可以中断&#xff0c;强行终断会抛出异常, 而reentrantlock可以调用线程的interrupt方法来中断等待&#xff0c;继续执行下面的代码。 在获取锁…

Windows 禁用 Defender

原文&#xff1a;https://blog.iyatt.com/?p8078 2024.4.4 Windows 11 专业版 23H2 Beta 预览版 进入安全中心&#xff0c;关闭所有&#xff0c;特别是篡改防护选项 打开注册表 地址栏粘粘路径 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows Defende…

IO和NIO的主要区别在哪里?

Java 中的 IO&#xff08;输入/输出&#xff09;和 NIO&#xff08;新输入/输出&#xff09;都是处理输入和输出操作的方式&#xff0c;它们的主要区别在于如何处理数据的读写。 阻塞与非阻塞: IO是阻塞的&#xff0c;这意味着当一个线程调用read()或write()时&#xff0c;该线…

【Clang+LLVM+honggfuzz学习】(二)honggfuzz的安装与试用

书接上篇【ClangLLVMhonggfuzz学习】&#xff08;一&#xff09;LLVM简介、安装和第一个Hello Pass 本篇介绍honggfuzz的安装与简单使用 本文架构&#xff0c;PS:可选择观看哦 前言git安装试用编写测试文件demo.c设置环境变量开始fuzzFuzz-ing疑问 前言 漏洞检测做毕设&#…