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」 如:photosmy_photos
  • 数据库表迁移名字 必须 为「复数」,如:2014_08_08_234417_create_photos_table.php
  • 数据填充文件名 必须 为「复数」,如:PhotosTableSeeder.php
  • 数据库字段名 必须 为「Snake Case」,如:view_countis_vip
  • 数据库表主键 必须 为「id」
  • 数据库表外键 必须 为「resource_id」,如:user_idpost_id
  • 数据模型变量 必须 为「resource_id」,如:$user_id$post_id

 有时候数据模型里的代码会变得很臃肿,应该 利用 Trait 来精简逻辑代码量,提高可读性,存放于文件夹:app/Models/Traits 文件夹中。

建议全部使用margration,包含数据库迁移数据填充

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 命令是根据配置信息

猜你喜欢

转载自blog.csdn.net/myarche/article/details/86466162