学习笔记:《Laravel5.3》

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

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');
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,565评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,021评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,003评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,015评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,020评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,856评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,178评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,824评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,264评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,788评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,913评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,535评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,130评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,102评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,334评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,298评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,622评论 2 343

推荐阅读更多精彩内容

  • 先说几句废话,调和气氛。事情的起由来自客户需求频繁变更,伟大的师傅决定横刀立马的改革使用新的框架(created ...
    wsdadan阅读 3,039评论 0 12
  • 校园失物招领平台开发 ——基于laravel框架构建最小内容管理系统 摘要 ​ 针对目前大学校园人口密度大、人群活...
    蓝莲花xzsky阅读 6,163评论 8 54
  • 原文链接 必备品 文档:Documentation API:API Reference 视频:Laracasts ...
    layjoy阅读 8,603评论 0 121
  • 最近在和同学参与一个创业项目,用到了laravel,仔细研究了一下,发现laravel封装了很多开箱即用的方法,通...
    MakingChoice阅读 3,298评论 0 0
  • 已经很晚了,婆婆收拾收拾去睡了;已经很晚了,小丫头搂着我的脖子被哄睡了;已经很晚了,老公才从外边回来,很疲惫的样子...
    火红的石榴暖暖阅读 183评论 0 0