lavarel5.2官方文档阅读——架构基础
《目录》
5.Facades外立面(从这节起,看中文版的:https://phphub.org/topics/1783)
1.请求的生命周期
所有的请求都会被服务器导向public/index.php文件,它是整个框架的入口点。首先载入Composer提供的类自动加载器,然后获取lavarel应用的一个实例(从bootstrap/app.php中)。
进来的所有请求,根据类型不同,要么送进HTTP kernel,要么就送进console kernel。kernel位于app/Http/Kernel.php中,它是Illuminate\Foundation\Http\Kernel类的子类,其中定义有bootstrappers数组,该操作在处理请求前首先被执行,对错误、日志等很多方面进行配置。其中,也定义了很多中间件,对session、CSRF验证、维护模式等进行处理。kernel中的handle方法可以看做是一个黑盒,输入为请求对象,输出为响应对象。
另一个重要的操作是载入service provider,它位于config/app.php的providers数组中,首先将执行所有provider的register函数,然后执行他们的boot函数。service provider可以提供database, queue, validation, 和routing方面的各种组件,它是lavar启动过程中最重要的一环。
这些都建立起来以后,请求将送至router,根据路由规则进行分发处理。
总而言之,service provider是laravel启动的关键,app实例被创建、service被注册、然后请求就交给app处理,如此简单!理解service provider是关键、它位于app/Providers中,默认地,可以在AppServiceProvider中添加自定义的启动代码、容器的绑定方式等;也可以创建单独的几个文件以负责更细粒度的provider。
2.应用的架构
lavarel并不会限制将类放在哪个目录下,只要是composer可以自动加载就可以。
目录结构如下:
app保存应用的核心代码
bootstrap保存启动框架的代码和一些自动加载配置等,cache是为了优化启动速度文件夹。
config包含所有的配置文件
database包含数据库的migration和seeds
public包含前端控制和静态文件
resources包含视图文件、本地化文件、和raw assets (LESS, SASS, CoffeeScript)等
storage包含编译好的blade模板、基于文件的session、缓存和其他一些由框架生成的文件。分为app文件夹(可以保存任何被框架使用的文件)、framework文件夹(保存生成的文件和缓存)、logs文件夹(保存所有的日志文件)。
tests文件夹包含测试代码
vendor文件夹包含composer依赖包 app文件夹详解(该文件夹中的许多类都可以通过artisan make命令生成):
Console和Http文件夹相当于是提供了框架核心功能的api,http和cli是两种与框架交互的方式,但是并没有功能性的代码,他们只会对应用发起一些命令。console中包含了artisan命令,http中包含了中间件、控制器、请求等。
Events文件夹是event类所在地,它提供了灵活和解耦的方式,以通知应用的其他部分某事件已发生。
Exceptions包含了异常处理类。
Jobs是队列任务的所在地,可以执行队列任务,也可以与现有的请求生命周期同步执行。
Listeners文件夹中是事件的handler所在地,例如UserRegistered事件就有可能是被SendWelcomeEmail监听器所处理的。
Policies文件夹是保存认证策略的地方,它决定登录用户可以对哪些资源进行哪些操作。
3.服务提供者Service Provider
// config/app.php中的providers数组是所有provider的列表,但是它们中的许多都是延迟加载,意味着只有在请求体需要时,它才进行载入。
// 所有的provider都继承Illuminate\Support\ServiceProvider抽象类,唯一必须实现的方法是register,其中只能写将起绑定到service container的代码。由下列命令生成一个provider:
php artisan make:provider RiakServiceProvider //下列是一个provider示例:
<?php namespace App\Providers; use Riak\Connection;
use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function register()//此处使用register方法在服务容器中定义了一个Riak\Connection类的实例,而且是“单例”
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection(config('riak'));
});
}
} //当我们想要注册一个view composer时,需要在boot方法中。boot方法的调用是在所有其他的provider都已经被注册后,所以在函数中可以使用框架提供的任何service。下面展示了boot的使用:
<?php namespace App\Providers; use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; class EventServiceProvider extends ServiceProvider
{
// Other Service Provider Properties... /**
* Register any other events for your application.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events); view()->composer('view', function () {
//
});
}
} //可以在boot方法中type-hint任何类,服务容器可以帮你完成依赖注入:
use Illuminate\Contracts\Routing\ResponseFactory; public function boot(ResponseFactory $factory)
{
$factory->macro('caps', function ($value) {
//
});
} //注册自己的provider,位于config/app.php中providers数组:
'providers' => [
// Other Service Providers App\Providers\AppServiceProvider::class,
], //通过设置provider的defer属性为true,并且定义一个provides方法,可以避免该provider每次请求时,都从文件系统中加载,只有在实际需要时,才真正加载进来。Lavarel会保存这些延迟加载的provider,还有他们对应的类名,仅当实际需要时,就可以加载进来:
<?php namespace App\Providers; use Riak\Connection;
use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true; /**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection($app['config']['riak']);
});
} /**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()//该方法只用返回注册到服务容器中的服务绑定名即可
{
return [Connection::class];
} }
4.服务容器Service Container
//首先,请参考https://phphub.org/topics/789以了解什么是服务容器、依赖注入等 //第一个示例:
//因为每购买一个podcast,就会发送邮件,这里将mailer作为依赖注入
<?php namespace App\Jobs; use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling; class PurchasePodcast implements SelfHandling
{
/**
* The mailer implementation.
*/
protected $mailer; /**
* Create a new instance.
*
* @param Mailer $mailer
* @return void
*/
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
} /**
* Purchase a podcast.
*
* @return void
*/
public function handle()
{
//
}
} //几乎所有的容器绑定都是在provider中的,在provider中,可以通过$this->app实例来访问container对象:
$this->app->bind('HelpSpot\API', function ($app) {//这里接受了app作为参数,以便我们可以通过app对象获取子依赖
return new HelpSpot\API($app['HttpClient']);
}); //单例模式
$this->app->singleton('FooBar', function ($app) {
return new FooBar($app['SomethingElse']);
}); //绑定一个具体对象
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar); //将接口绑定到一个特定实现
//第一个参数是接口,第二个参数是实现类
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
//在使用该接口的地方,就会自动注入该实现:
use App\Contracts\EventPusher; /**
* Create a new class instance.
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
} //上下文绑定Contextual Binding
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give('App\Services\PubNubEventPusher');
//绑定一个特定整数
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('$maxOrderCount')
->give(10); //通过标签管理
//当构建一个report集成器时,需要不同类型的report,此时将他们标注同一个标签,以实现一次性绑定全部
$this->app->bind('SpeedReport', function () {
//
});
$this->app->bind('MemoryReport', function () {
//
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
//使用时:
$this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports'));
}); //解析:
$fooBar = $this->app->make('FooBar');
$fooBar = $this->app['FooBar'];
//更常用的方式是在controller、listener、jobs、middleware等类的构造对象中进行type-hint,laravel可以自动解析依赖 //监听解析事件,使用resolving方法:
$this->app->resolving(function ($object, $app) {
// Called when container resolves object of any type...
});
//这种监听使得该类在解析时,进行监听函数调用,比如添加一些额外属性啥的,然后才返回给consumer
$this->app->resolving(FooBar::class, function (FooBar $fooBar, $app) {
// Called when container resolves objects of type "FooBar"...
});
5.Facades外立面
// 门面为应用的服务容器中的绑定类提供了一个“静态”接口。Laravel 内置了很多门面,你可能在不知道的情况下正在使用它们。Laravel 的门面作为服务容器中的底层类的“静态代理”
// 在 Laravel 应用的上下文中,门面就是一个提供访问容器中对象的类。该机制原理由 Facade 类实现
// 门面类只需要实现一个方法:getFacadeAccessor。正是 getFacadeAccessor 方法定义了从容器中解析什么(然后 Facade 基类使用魔术方法 __callStatic() 从你的门面中调用解析对象)
// Cache 门面继承 Facade 基类并定义了 getFacadeAccessor 方法,该方法的工作就是返回服务容器绑定类的别名,当用户引用 Cache 类的任何静态方法时,Laravel 从服务容器中解析 cache 绑定,然后在解析出的对象上调用所有请求方法(本例中是 get):
<?php namespace App\Http\Controllers; use Cache;
//注意我们在顶部位置引入了 Cache 门面。该门面作为代理访问底层 Illuminate\Contracts\Cache\Factory 接口的实现。我们对门面的所有调用都会被传递给 Laravel 缓存服务的底层实例。
use App\Http\Controllers\Controller; class UserController extends Controller{
/**
* 为指定用户显示属性
*
* @param int $id
* @return Response
*/
public function showProfile($id)
{
$user = Cache::get('user:'.$id); return view('profile', ['user' => $user]);
}
}
// Cache类的实现在Illuminate\Support\Facades\Cache
class Cache extends Facade{
/**
* 获取组件注册名称
*
* @return string
*/
protected static function getFacadeAccessor() {
return 'cache';
}
}
//下表列出了facade、底层类和container中的绑定名之间的关系:
Facade Class Service Container Binding
App Illuminate\Foundation\Application app
Artisan Illuminate\Contracts\Console\Kernel artisan
Auth Illuminate\Auth\AuthManager auth
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Bus Illuminate\Contracts\Bus\Dispatcher
Cache Illuminate\Cache\Repository cache
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
DB Illuminate\Database\DatabaseManager db
DB (Instance) Illuminate\Database\Connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Gate Illuminate\Contracts\Auth\Access\Gate
Hash Illuminate\Contracts\Hashing\Hasher hash
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\Writer log
Mail Illuminate\Mail\Mailer mailer
Password Illuminate\Auth\Passwords\PasswordBroker auth.password
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Contracts\Queue\Queue queue
Queue (Base Class) Illuminate\Queue\Queue
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\Database redis
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Blueprint
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store
Storage Illuminate\Contracts\Filesystem\Factory filesystem
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (Instance) Illuminate\Validation\Validator
View Illuminate\View\Factory view
View (Instance) Illuminate\View\View
6.用户认证
// 配置文件位于config/auth.php
// 在底层代码中,Laravel 的认证组件由“guards”和“providers”组成,Guard 定义了用户在每个请求中如何实现认证,例如,Laravel 通过 session guard来维护 Session 存储的状态、Cookie 以及 token guard,token guard 是认证用户发送请求时带的“API token”。
// Provider 定义了如何从持久化存储中获取用户信息
// 对应的数据表模型位于App\User,还有其对应的migration,位于database中
// Laravel 开箱提供了两个认证控制器,位于 App\Http\Controllers\Auth 命名空间下,AuthController 处理新用户注册和登录,PasswordController 用于帮助用户找回密码。每个控制器都使用 trait 来引入它们需要的方法。
use AuthenticatesAndRegistersUsers, ThrottlesLogins; // AuthController 中的自定义操作
// 自定义路径:
protected $redirectTo = '/home';
// 自定义Guard,该属性的值对应认证配置文件 auth.php 中的相应 guard 配置
protected $guard = 'admin';
// 自定义验证/存储
AuthController 的 validator 方法包含了新用户的验证规则,你可以按需要自定义该方法。
AuthController 的 create 方法负责使用 Eloquent ORM 在数据库中创建新的 App\User 记录。当然,你也可以基于自己的需要自定义该方法。 // 获取认证用户
$user = Auth::user();
// 或通过Illuminate\Http\Request实例访问
<?php namespace App\Http\Controllers; use Illuminate\Http\Request;
use Illuminate\Routing\Controller; class ProfileController extends Controller{
/**
* 更新用户属性.
*
* @param Request $request
* @return Response
*/
public function updateProfile(Request $request)
{
if ($request->user()) {
// $request->user() 返回认证用户实例...
}
}
} // 判断当前用户是否通过认证
if (Auth::check()) {
// The user is logged in...
} // auth中间件的使用,只允许通过认证的用户访问给定路由
// 使用路由闭包...
Route::get('profile', ['middleware' => 'auth', function() {
// 只有认证用户可以进入...
}]);
// 使用控制器...
Route::get('profile', [
'middleware' => 'auth',
'uses' => 'ProfileController@show'
]);
// 在Controller中使用:
public function __construct(){
$this->middleware('auth');
} // 指定一个Guard,在指定auth中间件时,也可以指定一个guard,确定其使用哪个(列表参见auth.php中的guards数组)
Route::get('profile', [
'middleware' => 'auth:api',
'uses' => 'ProfileController@show'
]); // 登录失败次数限制
如果你使用了 Laravel 内置的 AuthController 类, 可以使用 Illuminate\Foundation\Auth\ThrottlesLogins trait 来限制用户登录失败次数。默认情况下,用户在几次登录失败后将在一分钟内不能登录,这种限制基于用户的用户名/邮箱地址+IP地址。(这里如何设定次数???)
// 这个类中,设为5次,应该也可以重写这个值 vendor/laravel/framework/src/Illuminate/Foundation/Auth/ThrottlesLogins.php // 通过ID认证用户,要通过用户ID登录到应用,可以使用 loginUsingId 方法,该方法接收你想要认证用户的主键作为参数(用于测试):
Auth::loginUsingId(1); //一次性认证用户。你可以使用 once 方法只在单个请求中将用户登录到应用,而不存储任何 Session 和 Cookie,这在构建无状态的 API 时很有用。once方法和attempt方法用法差不多:
if (Auth::once($credentials)) {
//
}
【下面的内容不看了,都是具体的接口函数、等等,用的时候再看】
lavarel5.2官方文档阅读——架构基础的更多相关文章
- cassandra 3.x官方文档(2)---架构解析
写在前面 cassandra3.x官方文档的非官方翻译.翻译内容水平全依赖本人英文水平和对cassandra的理解.所以强烈建议阅读英文版cassandra 3.x 官方文档.此文档一半是翻译,一半是 ...
- hBase官方文档以及HBase基础操作封装类
HBase 官方文档 0.97 http://abloz.com/hbase/book.html HBase基本操作封装类(以课堂爬虫为例) package cn.crxy.spider.utils; ...
- [E] Shiro 官方文档阅读笔记 The Reading Notes of Shiro's Offical Docs
官方文档: https://shiro.apache.org/reference.html https://shiro.apache.org/java-authentication-guide.htm ...
- python2.7官方文档阅读笔记
官方地址:https://docs.python.org/2.7/tutorial/index.html 本笔记只记录本人不熟悉的知识点 The Python Tutorial Index 1 Whe ...
- 保存与恢复变量和模型,tensorflow官方文档阅读笔记
官方中文文档的网址先贴出来:https://tensorflow.google.cn/programmers_guide/saved_model tf.train.Saver 类别提供了保存和恢复模型 ...
- Spark SQL官方文档阅读--待完善
1,DataFrame是一个将数据格式化为列形式的分布式容器,类似于一个关系型数据库表. 编程入口:SQLContext 2,SQLContext由SparkContext对象创建 也可创建一个功能更 ...
- pandas官方文档阅读收获
1.当心它里面的简写: 第二张图中的输出实际上是等效于: df = df.drop() df 若只进行下面的操作,则drop操作不会起作用,因为它的inplace默认为False: df.drop() ...
- SpringMVC官方文档阅读
默认的DispatcherServlet配置 在spring-webmvc-4.3.16.RELEASE.jar/org/springframework/web/servlet/路径下的Dispatc ...
- iOS官方文档阅读 基本格式指北
一些关键词作用 NS_AVAILABLE 表示可用 如 NS_AVAILABLE(NA, 6_0);例如上面这句就是表示 该方法在6.0系统后可用 如果在6.0以下的系统用不了的 或者直接崩溃. NS ...
随机推荐
- cadence学习一------>介绍
Allegro常用组件: 1.orcad capture cis------>>原理图 2.PCB editor----->>PCB 3.PAD designer------- ...
- java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.M ...
- shutil&shelve
https://www.cnblogs.com/xiangsikai/p/7787101.html http://www.cnblogs.com/wupeiqi/articles/4963027.ht ...
- P4391 [BOI2009]Radio Transmission 无线传输(KMP)
题目描述 给你一个字符串,它是由某个字符串不断自我连接形成的. 但是这个字符串是不确定的,现在只想知道它的最短长度是多少. 输入输出格式 输入格式: 第一行给出字符串的长度,1 < L ≤ 1, ...
- OpenStack--Rabbitmq组件消息队列
概念 队列 MQ 全称为Message Queue,消息队列( MQ ) 是一种应用程序的通信方法.应用程序通过读写入列队的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们. 消息传递指的是 ...
- jQuery-委托事件和on方法注册事件
delegate注册委托事件 delegate--代理.委托 事件代理----事件最终不是由$("#first")执行,它只是代理元素 第一个参数:最终发生事件的元素 第二个参数: ...
- C++—模板(1)模板与函数模板
1.引入 如何编写一个通用加法函数?第一个方法是使用函数重载, 针对每个所需相同行为的不同类型重新实现这个函数.C++的这种编程机制给编程者极大的方便,不需要为功能相似.参数不同的函数选用不同的函数名 ...
- C#中判断DataReader是否为空的代码
下面的内容是关于C#中判断DataReader是否为空的内容. if(DataReader.HasRows){}
- Redis实战 - 3.Hash
hash Redis的Hash有点像一个对象(object),一个Hash里面可以存多个Key-Value对作为它的field,所以它通常可以用来表示对象. Hash里面能存放的值也能作为String ...
- elasticsearch 学习
docker run -p : -d elasticsearch #直接拉取运行 #指定条件搜索curl --request GET \ --url 'http://localhost:9200/im ...