美文网首页马文的地下室
学习笔记:《Laravel5.3》

学习笔记:《Laravel5.3》

作者: 马文Marvin | 来源:发表于2016-08-25 03:00 被阅读1130次

    过去做事情急,什么东西拿起来就用,不喜欢进行系统性的学习,造成在使用过程中的错误和低效,现在感觉自己耐心多了,用之前先系统的看一下文档,再接着用。

    Laravel 是“小丑鱼”项目技术团队共同确定下来的 PHP 程序框架,其近几年的发展异常迅猛,已经盖过了 YII 和 Symfony 的风头。Laravel 的发起人 Taylor Otwell 在 Blog 中说自己的偶像是 Symfony 的创始人 Fabien Potencier:《PHP Developers Who Have Inspired Me》

    Laravel 需要使用 composer 安装,然后安装 composer 本身又需要命令行支持https翻墙(后来知道其实下载也可以),https翻墙需要装 icu4c,icu4c 需要安装 brew,好在 ruby 已经系统安装了,不然这个循环还会继续下去。Laravel 最新版本对 PHP 版本的要求也比较高,要求 PHP >= 5.6.4,为此专门把本地 PHP 版本升了级。

    安装:

    1. 先安装好 Composer
    2. 全局安装 laravel/installer,一个 laravel 的安装工具
      composer global require "laravel/installer"
    3. 初始一个 laravel 的项目,然后就可以开始运行了
      $HOME/.composer/vendor/bin new project_name
    4. 建立 .env 文件
      cp .env.example .env
    5. 设置 APP_KEY
      ./artisan key:generate
    6. 设置权限(正式环境不要这么操作)
      chmod -R 777 .

    以下是阅读官方文档做的记录,基于5.2版本:

    目录结构

    这里解释的非常清楚:https://laravel-china.org/docs/5.4/structure

    在 Laravel 的开发过程中会用到许多不同类型的包管理工具,新生成很多的文件,这里简单说明一下:

    composer.json 是 composer 的配置文件
    /vendor 目录存放被 composer 安装的文件

    package.json 是 nodejs 的配置文件
    /node_modules 目录存放被 npm 安装的文件

    bower.json 是 bower 的配置文件
    .bowerrc 文件中设置了被 bower 安装的文件,一般设置为 /resources/assets/bower

    gulpfile.js 是 gulp 的配置文件

    框架核心结构

    Service Container:
    管理依赖注入(dependency injection)的容器工具,《唠唠依赖注入》 《唠唠Service Container》 两篇文章里面解释的比较清晰。

    Service Providers:
    包含了 Service Container、事件监听(event listeners)、中间件(middleware)、路由(routes)的整套实现机制的类。
    // Laravel Framework Service Providers... Illuminate\Auth\AuthServiceProvider::class, Illuminate\Broadcasting\BroadcastServiceProvider::class, Illuminate\Bus\BusServiceProvider::class, Illuminate\Cache\CacheServiceProvider::class, Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, Illuminate\Cookie\CookieServiceProvider::class, Illuminate\Database\DatabaseServiceProvider::class, Illuminate\Encryption\EncryptionServiceProvider::class, Illuminate\Filesystem\FilesystemServiceProvider::class, Illuminate\Foundation\Providers\FoundationServiceProvider::class, Illuminate\Hashing\HashServiceProvider::class, Illuminate\Mail\MailServiceProvider::class, Illuminate\Pagination\PaginationServiceProvider::class, Illuminate\Pipeline\PipelineServiceProvider::class, Illuminate\Queue\QueueServiceProvider::class, Illuminate\Redis\RedisServiceProvider::class, Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, Illuminate\Session\SessionServiceProvider::class, Illuminate\Translation\TranslationServiceProvider::class, Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, // Application Service Providers... App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class,

    HTTP层:

    Routing
    Laravel 非常尊重 CRUD,所以可以在表单里面添加:
    <input type="hidden" name="_method" value="PUT">

    路由中传递的 id 值可以根据名字直接返回带有了数据字段的 model(感觉这个有点太过于智能了):
    Route::get('api/users/{user}', function (App\User $user) { return $user->email; });

    Laravel 5.2 开始取消了 Route::controller() 这个方法,不能再方便得使用:

    Route::controller('user', 'UserController');

    官方文档中的解释是:

    The following features are deprecated in 5.2 and will be removed in the 5.3 release in June 2016:
    Implicit controller routes using Route::controller
    have been deprecated. Please use explicit route registration in your routes file. This will likely be extracted into a package.

    可能是为了让路由的定义更加的清晰化

    Middleware
    类似于 Symfony 的 FIlter,属于一个请求从 HTTP 层 进入到 APP 层,以及从 APP 层出去到 HTTP 层过程中可以添加处理的部分。

    CSRF Protection
    在表单中添加:
    {{ csrf_field() }}
    或者
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    然后 VerifyCsrfToken 这个中间件便会自动处理 CSRF,对于 AJAX 请求的保护,则可以在 meta 中插入:
    <meta name="csrf-token" content="{{ csrf_token() }}">
    再配合一段 JS 的程序来自动实现:
    $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });

    Controllers
    如果路由中没有指定某个具体的 Controller 方法,则指向一下叫做 __envoke() 的方法:
    public function __invoke($id) { return view('user.profile', ['user' => User::findOrFail($id)]); }

    中间件经常在 Controller 的构造方法中被指定:
    public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); }

    Controller 中有一套封装好的 CRUD,叫做 Resource Routes,感觉比较重,不大敢用。

    Controller 方法的第一个参数支持 Service Container,还是蛮有意思的,构造函数 __construct() 的第一个参数也支持,使用 Service Container 的方式是利用的 PHP 最新版本的新语法,在实践中看看会出现怎么样的运用机会,这种运用反射机制和 type-hint 结合而出现的使用方式,真的是丧心病狂......

    Requests & Responses
    Laravel 的 Requests & Responses 遵循着 PSR-7 standard 的标准,对上传和下载也做了相应的封装,东西比较多,这个具体使用的时候查文档

    Validation
    有一个叫做 bail 的参数可以帮助只返回首个验证不通过的信息:
    $this->validate($request, [ 'title' => 'bail|required|unique:posts|max:255', 'body' => 'required', ]);

    View 和 Template

    View
    View 可以进行判断:
    if (View::exists('emails.customer')) { // }

    如果你希望每个 Controller 中都可以共享一些值,也可以有方法可以实现,但是会有人记得用吗?
    public function boot() { View::share('key', 'value'); }

    View Composers
    如果你希望不同的 Controller 中的 View 可以共享一些数据,那么就可以引入 View Composers 的机制,不过个人感觉实践中没有特别的必要使用这个机制,太私人的业务逻辑归属会让代码不易维护

    Blade Templates
    Laravel 提供的一套轻量级的模板引擎,未来的架构会越来越趋向于前后端的分离,加之 PHP 语言本身具有较强的模板特性,内置一套轻量级的模板引擎是非常聪明的解决方案。

    涉及前端部分

    Laravel 结合使用了 Bootstrap 和 Vue 作为前端解决方案,然后提供了一个叫做 Laravel Elixir 的工具来进行前端 JS 和 CSS 的编译,同时这个编译过程支持 Less、Sass、Stylus、Plain CSS 这些 CSS 的同时编译,也支持 Webpack、Rollup、JavaScript 的结合编译。Laravel Elixir 本身是对 Gulp 的封装,而 Gulp 是基于 node.js 他们家的 npm,所以这个解决方案的安装过程也是丧心病狂,一路上 node.js、npm、Gulp、Laravel Elixir 安装完,等到真正使用的时候不知道还会遇到多少问题,成本啊!

    因为 Laravel Elixir 基于 Gulp,所以在编译的时候可以直接用 Gulp 的命令行工具:
    gulp // 编译命令 gulp watch // 只要 CSS 或者 JS 文件修改过了,就会自动编译

    余下的就是看 Bootstrap 和 Vue 的文档了

    涉及安全部分

    Laravel 提供了一个 Auth 静态类存放权限安全相关的代码,提供了 Gate 静态类处理认证相关的内容

    Authentication
    Laravel 对 Authentication 做了全局统筹,不仅仅注册好了路由,而且运行 php artisan make:auth 可以看到一个脚手架搭建好的小系统,方便学习:
    // Authentication Routes... $this->get('login', 'Auth\AuthController@showLoginForm'); $this->post('login', 'Auth\AuthController@login'); $this->get('logout', 'Auth\AuthController@logout'); // Registration Routes... $this->get('register', 'Auth\AuthController@showRegistrationForm'); $this->post('register', 'Auth\AuthController@register'); // Password Reset Routes... $this->get('password/reset/{token?}', 'Auth\PasswordController@showResetForm'); $this->post('password/email', 'Auth\PasswordController@sendResetLinkEmail'); $this->post('password/reset', 'Auth\PasswordController@reset');

    在数据安全方面,Laravel 提供了一套称为 Policy 的解决机制,Policy 机制可以在 Methods、Models、Filters、Authorizing Actions、Middleware、Controller Helpers、Blade Templates中进行使用

    文档中提到了涉及 Vue 的一套 API Authentication 解决方案,因为对 Vue 还不够了解,这块先放过,等学会了 Vue 以后再回过头来看这块的内容

    Laravel 提供了一个 encrypt helper 协助加密保护,使用 OpenSSL 和 AES-256-CBC cipher,反正都封装好了,只要用就是了

    Laravel 提供了一个 Hash 静态类产生和匹配用户密码,也是封装好了,用就可以

    一些零碎知识

    Event Broadcasting
    Laravel 提供了很详细的通讯解决方案,支持 Pusher、Redis、Socket.IO、Log 等等的驱动方案,提供了一个叫做 Laravel Echo 的 Javascript 工具包在前端部分进行支持,这块文档详细的提供了一个示例,等用到的时候可以参考

    Cache
    提供了一个 Cache 静态类操作缓存,支持 Memcached、Redis、文件、数据库缓存

    Events & Listeners
    这个应该是来源于 Symfony 的一套程序监听机制,但是感觉在大型系统中这样的方式会把业务逻辑搞的比较混乱,所以一直没有大规模使用过,但是前面 Event Broadcasting 的文档中强调了其重要性,可能在通讯解决方案中这样的监听机制是需要的,具体在使用的时候去理解

    文件系统使用的 Flysystem,Storage 这个静态类封装了文件管理的全部功能,远程(亚马逊A3、Rackspace等)、本地等等,各种文件相关的操作需求应有尽有

    邮件机制使用的是 SwiftMailer,SwiftMailer 本身是对 SMTP, Mailgun, SparkPost, Amazon SES, PHP's mail function, sendmail 等的封装,出自 SensioLabs,所以品质有保障

    Notifications
    消息机制是指给用户发提醒邮件、SMS信息、Slack、网页上的提醒信息等等,使用的 Notification 静态类进行了所有相关功能的封装

    Queues
    队列机制 Laravel 也提供了详细的支持,包括 Beanstalkd, Amazon SQS, Redis, 本地数据库等等

    这些零碎的知识,都是对一些较小应用场景的功能封装,对于这样的封装,最怕的就是不完善然后用户会跳过封装直接用相关的接口,维护起来也比较困难,所以无论过去封装成 PHP 组件,或者是成为某些框架的插件,都很难取得成功,更别提像 Laravel 这样包含在框架的核心代码里面,Laravel 能这么做,我想有一个原因是 composer 的出现让代码更高效的复用成为一种可能,即时是 Laravel 的核心库,也可以方便的和别的项目共享

    数据库相关

    Query Builder:Laravel 提供的一套数据库操作方法,基于 DB 这个 Facade 静态类,这里有详细的关于这个方法的接口说明:
    https://laravel.com/api/5.3/Illuminate/Database/Query/Builder.html

    Migrations:等到项目的业务逻辑到达一定的规模,会有 Migrations 方面的需求,在 Laravel 中体现为 Schema 这个 Facade 静态类

    Eloquent ORM:Laravel 提供的一套 ActiveRecord 实现,有一些很有趣的机制:

    Collections:提供了一整套强大的方法帮助检索返回数据的处理,很多的有用方法都支持 Lamda 表达式作为参数,非常有效的提升了代码的可读性。

    Accessors & Mutators:在 get 和 set 数据的时候分别加上了一层回调处理,对业务逻辑的分离非常有帮助。

    Date Mutators:实现一个 Carbon 的实例:
    https://github.com/briannesbitt/Carbon
    将类属性 $dates 中设定的相关字段自动转换成一个 Carbon 对象,可以调用所有 Carbon 中的相关方法。

    Attribute Casting:使用类属性 $casts 可以方便得对 get 到的字段数据进行属性设定,可以进行一层类型转换,可以设置的值有:integer, real, float, double, string, boolean, object, array, collection, date, datetime, timestamp

    Serialization:帮助查询数据在格式处理时候的两个方法 toArray() 和 toJson(),两个协调相应字段显示与否的类属性 $hidden 和 $visible,以及额外增加显示信息的 $appends 类属性

    pivot:在处理 ManyToMany 关系的时候,对于中间表专门提供的一个属性和方法协助方便处理

    Mass Assignment:提供了防止字段被错误插入数据的两个属性 $fillable 和 $guarded

    在插入数据的时候 firstOrCreate(), firstOrNew() 在提供一些列的查询条件后没有任何匹配结果,则直接进行插入

    findOrFail(), firstOrFail() 如果查询没有任何的结果,就抛出一个 ModelNotFoundException

    除了 One To One、One To Many、Many To Many 以外,laravel还提供了 Has Many Through(远层一对多关联:跨一个表进行一对多关联)、Polymorphic Relations(多态关联:某个字段多态关联不同的外表)、Many To Many Polymorphic Relations(多态的多对多关联)

    Eager Loading:关联查询的时候提高效率的机制,使用 with() 方法实现,传 Lamda 表达式的方法也是很赞:
    $users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get();

    Soft Deleting:Laravel 提供了整套的 Soft Deleting 解决方案,当然你不希望一个数据真正的从数据库删除的时候

    Query Scopes:查询作用域,将某些查询的条件绑定到某个 Model 上,比如 Soft Deleting 的时候,或者丢弃历史数据的时候,Query Scopes 就非常能帮得上

    chunk:当 crontab 操作的时候遇到30秒时间限制的时候,就可以用 Laravel 提供的这个 chunk() 方法来解决:
    http://laraveldaily.com/process-big-db-table-with-chunk-method/

    aggregate methods:count, max, min, avg, and sum,对查询结构数据进行操作的简单方法

    Seeding:一套伪造测试数据的方法,做单元测试之类的时候,会非常的有用

    附件

    Facades:一套静态类的基类接口,提供了 Laravel 整套的静态类标准解决方案,便于静态类全局使用
    'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class

    Contracts:前面的 Facades 是系统提供的一套静态类,但是如果你希望可以自定义这些功能的话,可以用 Contracts 来实现,Contracts 的作用是为你提供好了解耦的机制,方便自定义的时候直接套用,也是因为 Contracts 的存在,可以方便的找到很多现成的代码可以直接使用(防止第三方提供的代码具有耦合性)

    Contract 对应的 Facade
    Illuminate\Contracts\Auth\Factory Auth
    Illuminate\Contracts\Auth\PasswordBroker Password
    Illuminate\Contracts\Bus\Dispatcher Bus
    Illuminate\Contracts\Broadcasting\Broadcaster
    Illuminate\Contracts\Cache\Repository Cache
    Illuminate\Contracts\Cache\Factory Cache::driver()
    Illuminate\Contracts\Config\Repository Config
    Illuminate\Contracts\Container\Container App
    Illuminate\Contracts\Cookie\Factory Cookie
    Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
    Illuminate\Contracts\Encryption\Encrypter Crypt
    Illuminate\Contracts\Events\Dispatcher Event
    Illuminate\Contracts\Filesystem\Cloud
    Illuminate\Contracts\Filesystem\Factory File
    Illuminate\Contracts\Filesystem\Filesystem File
    Illuminate\Contracts\Foundation\Application App
    Illuminate\Contracts\Hashing\Hasher Hash
    Illuminate\Contracts\Logging\Log Log
    Illuminate\Contracts\Mail\MailQueue Mail::queue()
    Illuminate\Contracts\Mail\Mailer Mail
    Illuminate\Contracts\Queue\Factory Queue::driver()
    Illuminate\Contracts\Queue\Queue Queue
    Illuminate\Contracts\Redis\Database Redis
    Illuminate\Contracts\Routing\Registrar Route
    Illuminate\Contracts\Routing\ResponseFactory Response
    Illuminate\Contracts\Routing\UrlGenerator URL
    Illuminate\Contracts\Support\Arrayable
    Illuminate\Contracts\Support\Jsonable
    Illuminate\Contracts\Support\Renderable
    Illuminate\Contracts\Validation\Factory Validator::make()
    Illuminate\Contracts\Validation\Validator
    Illuminate\Contracts\View\Factory View::make()
    Illuminate\Contracts\View\View -

    Collections:对数组操作进行封装的一套方法,保留了 PHP 数组操作的巨大有点,同时又满足了方法的调用需求,不罗列了,可以直接看文档

    Helper Functions:70-80个左右的 Laravel 封装的函数,又一次对数组、字符串、Url等等的操作进行了扩展,看来 PHP 语言的函数总量,还是达不到 Laravel 的需求,在使用的过程中可以根据需求自己挖矿,不罗列了,可以直接看文档

    使用备忘(细节)

    Cookie:

    Cookie::queue('userId', 3, 1440);
    echo Cookie::get('userId');

    相关文章

      网友评论

      本文标题:学习笔记:《Laravel5.3》

      本文链接:https://www.haomeiwen.com/subject/yyjnsttx.html