过去做事情急,什么东西拿起来就用,不喜欢进行系统性的学习,造成在使用过程中的错误和低效,现在感觉自己耐心多了,用之前先系统的看一下文档,再接着用。
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 版本升了级。
安装:
- 先安装好 Composer
- 全局安装 laravel/installer,一个 laravel 的安装工具
composer global require "laravel/installer"
- 初始一个 laravel 的项目,然后就可以开始运行了
$HOME/.composer/vendor/bin new project_name
- 建立 .env 文件
cp .env.example .env
- 设置 APP_KEY
./artisan key:generate
- 设置权限(正式环境不要这么操作)
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 | |
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');
网友评论