Laravel5.5 项目开发文档,精简版,不适合新手使用。
Laravel5.5 开发规范
声明,本文档来自 laravel-china 社区,根据个人知识水平阅读记录。
原文地址:https://laravel-china.org/docs/laravel-specification/5.5
优点:高效编码,风格统一,减少错误
代码逻辑的灵活是件好事,但对团队协同开发而言,更多的选项确实累赘,所以请只选择,只知道,一种能覆盖大部分用例,且兼备开发效率的方法,再次碰到此需求,毫不犹豫的使用它。
请使用.test域名,ip地址:192.168.10.10
严格控制composer等各种扩展包的安装和加载,部署上线,请删除不使用的安装包
配置信息,请遵守如下:在.env中设置,config/app.php中通过env('name',null)使用,程序中使用config('name')获取
.env 文件中设置:
CDN_DOMAIN=cdndomain.com
config/app.php 文件中设置:
'cdn_domain' => env('CDN_DOMAIN', null),
程序中两种获取 相同配置 的方法:
env('CDN_DOMAIN')
config('app.cdn_domain')
自定义辅助函数必须放在app目录下
创建文件 app/helpers.php
<?php
// 示例函数
function foo() {
return "foo";
}
修改项目 composer.json
在项目 composer.json 中 autoload 部分里的 files 字段加入该文件即可:
{
...
"autoload": {
"files": [
"app/helpers.php"
]
}
...
}
然后运行:
$ composer dump-autoload
排版必须遵循 中文文案排版指北:https://github.com/sparanoid/chinese-copywriting-guidelines
代码根目录下,请书写readme.md行文规范
- 「项目概述」- 介绍说明项目的一些情况,类似于简单的产品说明,简单的功能描述,项目相关链接等,500 字以内;
- 「运行环境」- 运行环境说明,系统要求等信息;
- 「开发环境部署/安装」- 一步一步引导说明,保证项目新成员能最快速的,没有歧义的部署好开发环境;
- 「服务器架构说明」- 最好能有服务器架构图,从用户浏览器请求开始,包括后端缓存服务使用等都描述清楚(主要体现为软件的使用),配合「运行环境」区块内容,可作为线上环境部署的依据;
- 「代码上线」- 介绍代码上线流程,需要执行哪些步骤;
- 「扩展包说明」- 表格列出所有使用的扩展包,还有在哪些业务逻辑或者用例中使用了此扩展包;
- 「自定义 Artisan 命令列表」- 以表格形式罗列出所有自定义的命令,说明用途,指出调用场景;
- 「队列列表」- 以表格形式罗列出项目所有队列接口,说明用途,指出调用场景。
请团队最大化尽可能的保证开发工具统一
代码风格必须严格遵守 PSR-2 规范
绝对不在路由配置文件中书写必报路由和其他业务逻辑代码,因为一旦使用将无法使用路由缓存
请优先使用 Restful 路由,并配合资源控制器使用,见文档
超出 Restful 路由的,应该模仿上图的方式来定义路由
一般资源路由定义:
Route::resource('photos', 'PhotosController');
等于以下路由定义:
Route::get('/photos', 'PhotosController@index')->name('photos.index');
Route::get('/photos/create', 'PhotosController@create')->name('photos.create');
Route::post('/photos', 'PhotosController@store')->name('photos.store');
Route::get('/photos/{photo}', 'PhotosController@show')->name('photos.show');
Route::get('/photos/{photo}/edit', 'PhotosController@edit')->name('photos.edit');
Route::put('/photos/{photo}', 'PhotosController@update')->name('photos.update');
Route::delete('/photos/{photo}', 'PhotosController@destroy')->name('photos.destroy');
使用 resource
方法时,如果仅使用到部分路由,必须 使用 only
列出所有可用路由:
Route::resource('photos', 'PhotosController', ['only' => ['index', 'show']]);
绝对不是用 except ,因为 only 相当于白名单
资源路由必须使用复数模式;
/photos/create
/photos/{photo}
在允许使用路由模型绑定的地方必须使用
模型绑定代码 必须 放置于 app/Providers/RouteServiceProvider.php
文件的 boot
方法中:
public function boot()
{
Route::bind('user_name', function ($value) {
return User::where('name', $value)->first();
});
Route::bind('photo', function ($value) {
return Photo::find($value);
});
parent::boot();
}
全局路由参数,出去安全考虑,应该使用全局路由参数限制,见文档
必须 在 RouteServiceProvider
文件的 boot 方法里定义模式:
/**
* 定义你的路由模型绑定,模式过滤器等。
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot(Router $router)
{
$router->pattern('id', '[0-9]+');
parent::boot($router);
}
模式一旦被定义,便会自动应用到所有使用该参数名称的路由上:
Route::get('users/{id}', 'UsersController@show');
Route::get('photos/{id}', 'PhotosController@show');
只有在 id 为数字时,才会路由到控制器方法中,否则 404 错误。
获取url的优先级,请遵循如下:
在 Model 中创建 link() 方法:
public function link($params = [])
{
$params = array_merge([$this->id], $params);
return route('models.show', $params);
}
所有单个模型数据链接使用:
$model->link();
// 或者添加参数
$model->link($params = ['source' => 'list'])
『单个模型 URI』经常会发生变化,这样做将会让程序更加灵活。
除了『单个模型 URI』,其他路由 必须 使用 route 来获取 URL:
$url = route('profile', ['id' => 1]);
无法使用 route 的情况下,可以 使用 url 方法来获取 URL:
url('profile', [1]);
模型请必须放在 app/Models/ 文件夹中,并修改命名空间 App/Models ,为了不破坏原有的逻辑点,请全局搜索App/User 并替换为 App/Models/User
所有的Eloquent 数据模型 都必须继承统一的基类 App/Models/Model 位置在 /app/Models/Model.php,示例如下:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as EloquentModel;
class Model extends EloquentModel
{
public function scopeRecent($query)
{
return $query->orderBy('created_at', 'desc');
}
}
以 Photo 数据模型作为例子继承 Model 基类:
<?php
namespace App\Models;
class Photo extends Model
{
protected $fillable = ['id', 'user_id'];
public function user()
{
return $this->belongsTo(User::class);
}
}
数据模型相关的命名规范:
- 数据模型类名
必须
为「单数」, 如:App\Models\Photo
- 类文件名
必须
为「单数」,如:app/Models/Photo.php
- 数据库表名字
必须
为「复数」,多个单词情况下使用「Snake Case」 如:photos
,my_photos
- 数据库表迁移名字
必须
为「复数」,如:2014_08_08_234417_create_photos_table.php
- 数据填充文件名
必须
为「复数」,如:PhotosTableSeeder.php
- 数据库字段名
必须
为「Snake Case」,如:view_count
,is_vip
- 数据库表主键
必须
为「id」 - 数据库表外键
必须
为「resource_id」,如:user_id
,post_id
- 数据模型变量
必须
为「resource_id」,如:$user_id
,$post_id
有时候数据模型里的代码会变得很臃肿,应该 利用 Trait 来精简逻辑代码量,提高可读性,存放于文件夹:app/Models/Traits
文件夹中。
Model 全局作用域,所有的全局作用域都必须统一使用 "闭包定义全局作用域" 如下:
/**
* 数据模型的启动方法
*
* @return void
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope('age', function(Builder $builder) {
$builder->where('age', '>', 200);
});
}
控制器必须优先使用 Restful 资源控制器 。
必须 使用资源的复数形式,如:类名:PhotosController 文件名:PhotosController.php
保持短小精炼,方法名要求取名合理,不需要过多注释,为一些复杂的逻辑代码块书书写注释,不应该在控制器中书写私有方法,控制器里应该只存放路由动作方法。控制器中所有的方法都应该被使用,没用的应该删除,绝不再控制器中批量注释代码
视图优先使用.blade.php为后缀,保持目录结构清晰:
- layouts - 页面布局文件 必须 放置于此目录下;
- common - 存放页面通用元素;
- pages - 简单的页面存放文件夹,如:about、contact 等;
- resources - 对应 Restful 路由的资源路径名称,以 URI
photos/create
为例,对应create.blade.php
文件,存放在文件夹photos
下。
局部视图文件 必须 使用 _ 前缀来命名,如:photos/_upload_form.blade.php
视图命名 必须 使用资源视图的命名方式
很多情况下,创建和编辑视图里的页面结构接近相似,在这种情况下,应该 使用 create_and_edit.blade.php 视图。
必须 使用 表单请求 - FormRequest 类 来处理控制器里的表单验证。
绝不 使用 authorize() 方法来做用户授权,用户授权我们会单独使用 Policy 授权策略 来实现。
所有 FormRequest 表验证类 必须 继承 app/Http/Requests/Request.php 基类。基类文件如下:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class Request extends FormRequest
{
public function authorize()
{
// Using policy for Authorization
return true;
}
}
FormRequest 表验证类 必须 遵循 资源路由 方式进行命名,photos 对应 app/Http/Requests/PhotoRequest.php。
<?php
namespace App\Http\Requests;
class PhotoRequest extends Request
{
public function rules()
{
switch($this->method())
{
// CREATE
case 'POST':
{
return [
// CREATE ROLES
];
}
// UPDATE
case 'PUT':
case 'PATCH':
{
return [
// UPDATE ROLES
];
}
case 'GET':
case 'DELETE':
default:
{
return [];
};
}
}
public function messages()
{
return [
// Validation messages
];
}
}
必须使用授权策略类来做用户授权。
使用基类 所有 Policy 授权策略类 必须 继承 app/Policies/Policy.php 基类。基类文件如下:
<?php
namespace App\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
class Policy
{
use HandlesAuthorization;
public function __construct()
{
//
}
public function before($user, $ability)
{
if ($user->isAdmin()) {
return true;
}
}
}
Policy 授权策略类 必须 遵循 资源路由 方式进行命名,photos 对应 /app/Policies/PhotoPolicy.php 。
Policy 授权策略类文件内容请参考以下:
<?php
namespace App\Policies;
use App\Models\User;
use App\Models\Photo;
class PhotoPolicy extends Policy
{
public function update(User $user, Photo $photo)
{
return $user->isAuthorOf($photo);
}
public function destroy(User $user, Photo $photo)
{
return $user->isAuthorOf($photo);
}
}
应该 使用 自动判断授权策略方法,这样控制器和授权类的方法名就统一起来了。
/**
* 更新指定的文章。
*
* @param int $id
* @return Response
*/
public function update($id)
{
$post = Post::findOrFail($id);
// 会自动调用 `PostPolicy` 类中的 `update` 方法。
$this->authorize($post);
// 更新文章...
}
测试数据填充的两种方式:
工厂类:database\factories\UserFactory.php, 里面内容如下
use Faker\Generator as Faker;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define(App\Models\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => str_random(10),
'created_at' => \Carbon\Carbon::now()->toDateTimeString(),
'updated_at' => \Carbon\Carbon::now()->toDateTimeString(),
];
});
然后你可以在控制器中执行后者放到Database\Seeder\DatabaseSeeder.php中通过seed命令执行
php artisan make:seeder UsersTableSeeder
运行 Seeders
完成 seeder 类的编写之后,你可能需要使用 dump-autoload 命令重新生成 Composer 的自动加载器:
composer dump-autoload
接着就可以使用 Artisan 命令 db:seed 来填充数据库了。默认情况下,db:seed 命令将运行 DatabaseSeeder 类,这个类可以用来调用其它 Seed 类。不过,你也可以使用 --class 选项来指定一个特定的 seeder 类:
php artisan db:seed
php artisan db:seed --class=UsersTableSeeder
你也可以使用 migrate:refresh 命令来填充数据库,该命令会回滚并重新运行所有迁移。这个命令可以用来重建数据库:
php artisan migrate:refresh --seed
所有的自定义命令,都必须有项目的命名空间:
php artisan phphub:clear-token
php artisan phphub:send-status-email
必须使用Carbon来处理日期的和时间相关的操作,需要在 config/app.php 配置 'locale' => 'zh-CN'
Auth 中间件 必须 书写在控制器的 __construct 方法中,并且 必须 使用 except 黑名单进行过滤,这样当你新增控制器方法时,默认是安全的。
public function __construct()
{
$this->middleware('auth', [
'except' => ['show', 'index']
]);
}
项目上线后,开启配置信息和路由缓存
生产环境中的 应该 使用『配置信息缓存』来加速 Laravel 配置信息的读取。
使用以下 Artisan 自带命令,把 config 文件夹里所有配置信息合并到一个文件里,减少运行时文件的载入数量:
php artisan config:cache
缓存文件存放在 bootstrap/cache/ 文件夹中。
可以使用以下命令来取消配置信息缓存:
php artisan config:clear
路由缓存
缓存文件存放在 bootstrap/cache/ 文件夹中。另外,路由缓存不支持路由匿名函数编写逻辑,详见:文档 - 路由缓存。
php artisan route:cache
php artisan route:clear
类映射加载优化
php artisan optimize --force
php artisan clear-compiled
注意:此命令要运行在 php artisan config:cache 后,因为 optimize 命令是根据配置信息