Laravel 5프로젝트 구조 분석 및 중국어 문서 읽기 요약
HTTP경로
미들웨어
컨트롤러
HTTP요청
HTTP 응답
보기
서비스 공급자
서비스 컨테이너
계약
외관
요청 수명주기
캐시
수집
장인 콘솔
확장 프레임 *
라라벨 엘릭서*
암호화
오류 및 로그
파일 시스템 / 클라우드 스토리지
해시
도우미 방법
현지화*
메일*
확장팩 개발*
페이지 매김*
대기열*
세션
블레이드템플릿
단위 테스트*
데이터 검증
구조 Generator
마이그레이션 및 데이터 채우기
HTTP 라우팅
기본 라우팅
은 다양한 Http 메서드에 대한 경로를 정의합니다. 예:
경로::get('/', function(){
경로::게시물('foo/bar', function(){
경로 ::match(['get', 'post'], '/', function(){ # 여러 메소드
경로::모든('foo', function(){ # 모든 방법
url 메소드를 사용하여 url을 생성합니다. $url = url('foo');
CSRF보호
Laravel은 자동으로 각 사용자의 세션에 임의의 토큰을 배치합니다. VerifyCsrfToken 미들웨어는 세션 쌍에서 요청하고 입력한 토큰을 저장합니다. 토큰을 확인합니다. 미들웨어는 "POST" 매개변수로 CSRF 토큰 을 찾는 것 외에도 X도 확인합니다. -XSRF-TOKEN요청 헤더.
CSRF 토큰을 양식에 삽입하세요.
은 Blade 템플릿 엔진 :
추가 요청 헤더의 X-XSRF-TOKEN으로:
csrf_token() }}" />
$.ajaxSetup({
헤더: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]') .attr(' 내용')
}
});
...
# 이쪽으로ajax 요청에는 다음 헤더 정보가 포함됩니다:
$.ajax({
url: "/foo/bar",
})
방법 부정행위
< ;input type ="hidden" name="_method" value="PUT">
경로 매개변수
경로: :get( 'user/{id}', function($id){ # 기본 매개변수
Route::get('user/{name?}', function($name = null){ # 선택 매개변수
Route::get('user/{name?}', function($ name = 'John'){ # 기본값이 있는 매개변수
RouteServiceProvider의 boot 메서드에서 모드를 정의할 수 있습니다.
$router->pattern('id', '[0-9]+');
은 다음 특정 매개변수를 사용하는 모든 경로에 적용됩니다.
경로:: get ('사용자/{id}', 함수($id)
if ($route->input('id') == 1){ # 경로 외부 매개변수 가져오기
종속성 주입을 통해 매개변수를 얻을 수도 있습니다.
IlluminateHttp 사용요청;
Route::get('user/{id } ', function(요청 $request, $id){
if ($요청->route('id')){
경로 이름
Route::get('user/profile', ['as' => 'profile' , function(){
# 컨트롤러 작업에 대한 경로 지정 이름
경로::get('사용자/프로필', [
'으로' => '프로필',
'사용' = > 'UserController@showProfile'
]);
# 리디렉션에 명명된 경로 사용
$url = route('프로필');
$redirect = redirect()-> 🎜>경로('프로필');
# 현재 경로 요청의 이름을 반환
$name = Route::currentRouteName ( ; 공유 속성을 Route::group첫 번째 매개변수:
#과 같은 배열로 처리합니다. 공유 미들웨어
경로::그룹([
'미들웨어'=> ['foo', 'bar']], function()
{경로::get('/', function() {
// Foo And Bar 미들웨어 있음
});
Route::get('user/profile', function()
});
# 위의 예에서
foo 및 bar
는 미들웨어 키 이름입니다. 맞춤형 미들웨어의 키 이름과 클래스 이름 간의 매핑 관계를 Kernel.php
에 추가해야 합니다.
#
공유 네임스페이스
경로::group(['네임스페이스'
=> 'Admin'], function(){ // "AppHttpControllersAdmin" 네임스페이스 내의 컨트롤러 Route::group([
'namespace' => 'User'], function()
{
// "AppHttpControllersAdminUser" 네임스페이스 내의 컨트롤러 });
});
하위 도메인 이름 라우팅
Route::group(['domain' => ' {계정}.myapp.com'], function()
{
Route::get('user/{id}', function($account
, $id)
{
//
});
})
라우팅 접두사 경로 ::group([
'접두사' => 'admin'], function()
{
Route::get('users', function()
{
// "
/admin/users" URL
과 일치 });
});
#
경로 접두사에 매개 변수 정의
Route::group([ ' 접두사' => '계정/{계정_ID}'], function()
{
Route::get('detail', function($account_id)
{
//
});
});
라우팅 모델 바인딩
모델 바인딩은 경로에 모델 엔터티를 삽입하는 편리한 방법을 제공합니다. 주입과 비교 User ID, 주어진 ID와 일치하는 User 클래스 엔터티를 삽입하도록 선택할 수 있습니다. RouteServiceProvider::boot 메서드에서 모델 바인딩을 정의합니다.
공용 함수 boot(Router $ 라우터)
{
parent::boot($router);
$router->모델('user', 'AppUser');
}
그런 다음 {user} 매개변수를 사용하여 경로를 정의합니다.
Route::get('profile/{user}', function(AppUser $user){
//
});
profile/1에 요청하면 ID가 삽입됩니다. 은 1의 사용자 엔터티입니다. 엔터티가 존재하지 않으면 404을 발생시킵니다. 클로저를 찾을 수 없을 때의 동작을 정의하기 위해 세 번째 매개변수로 클로저를 전달할 수 있습니다.
던지기404오류
두 가지 방법:
abort(404) # 기본적으로; , SymfonyComponentHttpKernelExceptionHttpException이 특정 상태 코드와 함께 발생합니다.
또는: 수동으로 HttpException
미들웨어
새 미들웨어 만들기
php artisan make:middleware OldMiddleware # 새 미들웨어 만들기
미들웨어의 주요 기능은 handle() 메소드에서 구현됩니다:
class OldMiddleware {
공용 함수 핸들($request, Closure $next){
if (xxx){
return redirect('xx');
}
반품 $next( $요청);
}
}
구조를 분석해 보면 기본적으로 판단을 한 뒤 방향을 바꾸거나 앞으로 나아가는 것을 알 수 있다.
글로벌 미들웨어
모든 HTTP 요청에 의해 미들웨어가 실행되도록 하려면 미들웨어 클래스를 app/Http/Kernel 에 추가하세요. php의 $middleware 속성 목록입니다.
라우팅에 미들웨어 할당
새 미들웨어를 생성한 후 $routeMiddleware의 app/Http/Kernel.php에 추가합니다. 미들웨어 키 이름과 클래스 이름 간의 매핑 관계를 확인한 다음 경로에서 이 키 이름을 사용하여 경로를 할당합니다.
Route::get( ' admin/profile', ['middleware' => 종료 가능한 미들웨어
종료 가능한 미들웨어는 다음에서 상속해야 합니다. TerminableMiddleware
, 그리고 HTTP 다음에 실행될 수 있는
terminate() 메서드를 구현합니다. app/Http/Kernel.php의 전역 미들웨어 목록에 종료 미들웨어를 추가해야 합니다. 컨트롤러
기본 컨트롤러
모든 컨트롤러는 기본 컨트롤러 클래스를 확장해야 합니다.
AppHttpControllersController 사용;
class UserController 컨트롤러 확장 { # 상속컨트롤러
공개 함수 showProfile($id) # Action
{
AppHttpControllersController은 다음과 같이 정의됩니다:
네임스페이스 BorogadiHttpControllers;
IlluminateFoundationBusDispatchesJobs; 🎜>IlluminateRoutingController를 BaseController로 사용;
IlluminateFoundationValidationValidatesRequests 사용;
추상 클래스 Controller 확장
BaseController{
DispatchesJobs를 사용합니다. ValidatesRequests;
}
궁극적으로IlluminateRoutingController 클래스.
# 이름이 지정된 컨트롤러 경로
Route::get('foo', ['uses' => 'FooController@method', 'as' => '이름']);
# 은
을 가리킵니다. URL
$url = 액션('AppHttpControllersFooController@method');
또는:
URL::setRootControllerNamespace ('AppHttpControllers');
$url = action('FooController@method')
# 실행 중인 컨트롤러 액션 이름을 가져옵니다
$action = 경로::currentRouteAction();
컨트롤러 미들웨어
두 가지 방법 중 하나는 컨트롤러 경로에 지정하는 것입니다.
Route::get('profile', [
'미들웨어' => '인증',
'사용' => 'UserController@showProfile'
]);다른 하나는 컨트롤러 생성자에서 직접 지정하는 것입니다.
클래스 UserController 확장 컨트롤러 {
공용 함수 __construct(){
$this->미들웨어('auth');
$this->미들웨어('log', ['only' => ['fooAction', 'barAction']]);
암시적 컨트롤러
암시적 컨트롤러 구현은 단일 경로를 정의합니다. 컨트롤러에서 각 작업을 처리합니다.
경로 정의:
경로:: Controller('users', 'UserController');
컨트롤러 클래스 구현 정의:
클래스 UserController는 BaseController를 확장합니다. 🎜>#
응답사용자
public function postProfile( ){
#사용자/프로필
공개 기능에서 게시물에 응답하세요. anyLogin(){
#user/login의 모든 메소드에 응답합니다. "-"을 사용하여 여러 단어 컨트롤러 동작을 지원할 수 있습니다. public function getAdminProfile() {} # users/admin-profile에 대한 응답, user/adminprofile이 아님. 액션 이름 RESTfulResource Controller에 사용된 Camel Case 명명 방법에 유의하세요. 은 실제로 암시적 컨트롤러의 특정 응용 프로그램입니다. 경로 캐시 애플리케이션이 컨트롤러 라우팅만 사용하는 경우 경로 캐싱을 사용하여 성능을 향상시킬 수 있습니다. php artisan Route:cache 캐시된 경로 파일이 대신 사용됩니다. app/Http/routes.php파일 HTTP 요청 요청 받기 두 가지 방법 중 하나는 파사드 요청: 요청 사용 $name = 요청::input('name'); 또는 종속성 주입을 통해: 컨트롤러 의 생성자나 메서드에서 클래스에 대한 유형 힌트를 사용하세요. 현재 요청된 인스턴스는 서비스 컨테이너에 의해 자동으로 삽입됩니다. :
IlluminateHttpRequest 사용;
IlluminateRoutingController 사용;
class UserController는 Controller {
공용 함수 저장소(요청 $request){
$name = $request->input('name');
라우팅 매개변수, 라우팅 매개변수를 다른 종속성 뒤에 배치하면 됩니다.
public function update(Request $request,$id){
입력 데이터 가져오기
$name = 요청::
input('name') # 특정 입력 데이터 가져오기
$name = Request::input('name', 'Sally')# 특정 입력 데이터를 가져오지 않으면 가져옵니다. 기본값 가져오기
if (요청::has('name')){ # 입력데이터가 있는지 확인
$input = 요청::all (); >만('사용자 이름', '비밀번호') # 입력 데이터의 일부 가져오기
$input = 요청::제외('credit_card') # 부분 입력 데이터 제외 방법 가져오기
$input = Request::input('products.0.name') # 배열 형식으로 데이터 가져오기
이전 입력 데이터 요청::
flash()
# 현재 입력 데이터를 세션
中요청::flashOnly('사용자 이름', '이메일') ; # 세션
에 일부 데이터 저장 요청:: flashExcept('password') # 데이터의 일부를 세션으로 저장
, 제거 방법return 리디렉션('form')->withInput(); # 현재 입력 데이터를 세션
으로 리디렉션하고 캐시합니다.
return 리디렉션('form')->withInput(요청::제외('password')) # 현재 기간에 입력된 데이터의 일부를 세션
$username = 요청:: old('username'); # 일회성 세션 받기
{{ old('username') }} # 은 blade 템플릿에 표시됩니다. Old 입력 데이터
쿠키
Laravel Laravel이 생성한 쿠키는 암호화되어 인증됩니다.
$value = 요청::쿠키('이름') # 가져오기쿠키값
# 응답에 쿠키 추가
$response = new IlluminateHttpResponse('Hello World' );
$response->withCookie(cookie('name', 'value', $ 분));
$response->쿠키 포함(cookie()->forever('name', 'value')) # 영구적으로 유효한 쿠키
#
큐 모드에 쿠키를 추가합니다. 즉, 실제 세트 Cookie
Cookie::queue('name', 'value' 응답을 보내기 전 );
응답 반환('Hello World');
파일 업로드
$file = 요청::file('photo') #
업로드된 파일 가져오기
if (Request::hasFile('photo')) #파일 업로드 여부 확인
if (Request::file('photo')->isValid()) #업로드한 파일이 유효한지 확인
Request::file('photo')->move($destinationPath) #업로드된 파일 이동
Request::file('photo')->move($destinationPath, $fileName) #업로드된 파일을 이동하고 이름을 바꿉니다
기타요청사항
$uri = 요청: :path();
# 요청 받기 URI
if (요청:: ajax())# 요청에서 AJAX를 사용하는지 확인
#
요청 결정 방법
$method = 요청: :method();if (요청::isMethod('post'))
if (Request::is('admin/*'))
# 요청 경로가 특정 형식을 따르는지 확인
$url = 요청::url()# 요청 받기URL
HTTP 응답
기본 응답
Route::get('/', function(){
# 반환 문자열
'Hello World' 반환;
#
전체 Responses 인스턴스를 반환합니다. 두 가지 방법이 있습니다.
응답 반환객체:
IlluminateHttpResponse 사용반환( new
응답($content, $status))
—> ;헤더 ('Content-Type', $value);
또는 응답 사용 도우미 메서드: return 응답($content, $status)->header('Content-Type', $value); # 보기로 돌아가기 return response()->view('hello')->header('Content-Type', $type); # 쿠키 추가쿠키 응답 반환($content)->withCookie(cookie('name', 'value')); 리디렉션 돌아가기 리디렉션('user/login'); # 리디렉션리디렉션 방법 return 리디렉션('사용자/로그인')->with('message', '로그인 실패') # 현재 데이터를 세션 return 리디렉션()-> back(); return redirect()->route('login') # 리디렉션 특정 경로 # 매개변수를 사용하여 특정 경로로 리디렉션 return 리디렉션()->route('profile', [1]) 경로의 URI is: profile/{id} return 리디렉션()-> Route('profile', [' user' => 1]); # 라우팅된 URI 는 다음과 같습니다. profile/{user} # 컨트롤러 작업에 따른 리디렉션 return 리디렉션()-> ('AppHttpControllersHomeController@index'); # 매개변수 포함 기타 응답# json 반환 응답()-> json(['name' => 'Abigail', 'state' => 'CA']) # Return response()->json([' name' => 'Abigail', 'state' => 'CA']) setCallback 파일 다운로드 응답 반환()->download($pathToFile, $name, $headers); 응답 매크로 # 응답 매크로 정의는 일반적으로 boot 메소드에서 정의됩니다. 🎜>제공자 응답::매크로 ('caps' , function($value) use ($response){ # PHP기본적으로 익명 함수는 PHP의 컨텍스트 변수를 호출할 수 없습니다. 있지만 use 키 문자를 사용해야 합니다. use는 변수를 클로저에 복사하고 와 같은 참조 형식도 지원합니다. return $response->make(strtoupper($value)); }); # 통화 응답 매크로 반환 응답()->caps('foo'); 보기 기본보기 # 보기 정의 파일 경로 및 파일 이름: resources/views/greeting.php
# 통화 보기 경로::get( '/', function()
{ '인사말', [ => '제임스']) # Pass 뷰의 매개변수는 키-값 쌍의 배열입니다 }); # 하위 폴더 보기 호출 정의 위치: resources/views/ admin/profile.php 반환 보기(' admin.profile', $data); # 뷰에 데이터를 전달하는 다른 방법 with # 기존 방식 $view = view('greeting')->withName('빅토리아'); # 마법의 방법 $view = view('greetings ', $data); # 배열을 직접 전달합니다. $data는 키-값 쌍의 배열입니다. # 모든 보기에 데이터 공유 Provider를 사용자 정의하거나 AppServiceProvider의 boot 방법: view()->share('데이터', [1, 2, 3]) ; 또는: 보기::공유( 'data', [1, 2, 3 ]); # if (view()-> 존재('emails.customer' )) # 파일 경로에서 뷰 생성return view()-> file($pathToFile, $data); View 구성 요소View 구성 요소는 클로저 또는 클래스 메서드입니다. 뷰가 렌더링되기 전에 호출됩니다. # 뷰 구성 요소 정의 보기 사용;IlluminateSupportServiceProvider 사용; class ComposerServiceProvider는 ServiceProvider를 확장합니다. { 공용 함수 boot(){ 보기:: composer ('profile', 'AppHttpViewComposersProfileComposer'); # 보기:: composer('dashboard', function($view){ # 클로저를 사용하여 뷰 구성 요소 지정 ... }); } ... } 뷰 구성 요소를 지정하려면 클래스를 사용하세요. 지정된 클래스의 라는 메서드가 뷰가 렌더링되기 전에 호출됩니다. 위의 예에서와 같이 ProfileComposer' php 네임스페이스 AppHttpViewComposers ; IlluminateContractsViewView 사용; IlluminateUsersRepository를 UserRepository로 사용 보호된 $users; 공개 함수 __construct(UserRepository $users){ # 서비스 컨테이너 는 필수 매개변수 <🎜 > > (View $view){ # compose 메소드가 의 인스턴스에 전달됩니다. 여기서 매개변수는 View
$view->with('count', $this->users로 전달할 수 있습니다. ->count()); }} # in view 구성 요소 내에서 와일드카드 사용 View::composer('*', function($view){ # 모든 뷰 정의와 동일 # 여러 뷰에 동시에 뷰 연결 구성요소 View::composer(['profile', 'dashboard'], 'AppHttpViewComposersMyViewComposer'); # View::composers([ 'AppHttpViewComposersAdminComposer' => ['admin.index', 'admin.profile'],
'AppHttpViewComposersUserComposer' => '사용자', 'AppHttpViewComposersProductComposer' => ; '제품' ]); 서비스 제공업체 모든 사용자 정의 Provider는 IlluminateSupportServiceProvider Providersarray config/app.php 에 등록하세요. 사용자 정의된 는 등록 중 동작을 정의하는 데 사용되는 register() 메서드 를 정의해야 합니다. 또한 두 개의 선택적 메소드와 하나의 선택적 속성이 있습니다: boot()method 모든 Provider에는 로드된 후 호출되며 provides() 메소드 는 $defer 선택적 속성과 함께 사용됩니다. 🎜>에서는 버퍼링 기능을 제공하기 위해 협력하고 있습니다. 서비스 제공자를 통한 서비스 제공 아이디어 : 실제 작업을 완료하는 클래스 구현 및 제공자 정의 , Provider의 register() 메서드를 사용하여 실제 작업 클래스를 등록하고 실제 작업 클래스 인스턴스를 가져옵니다. 시스템 컨테이너. 그런 다음 이 공급자를 애플리케이션 구성에 등록하세요. 이렇게 애플리케이션이 초기화되면 모든 Provider의 register() 메서드가 호출되어 간접적으로 방법을 등록하게 됩니다. 실제 노동 계급 인스턴스를 얻으려면. # 기본 공급자 정의 안녕하세요, name ?>
use IlluminateSupportServiceProvider;
클래스 RiakServiceProvider 확장 ServiceProvider {
공개 기능
등록(){
# 컨테이너에 클래스를 등록하고 해당 인스턴스를 얻는 방법
$this->app- >싱글턴
('RiakContractsConnection', function($app){['config'][ '리아크']);
});
}
}
서비스 컨테이너
기본 사용법
Provider 내부에서 $this->app 서비스 컨테이너에 액세스합니다.
종속성을 등록하는 방법에는 콜백 인터페이스 메서드와 바인딩 인스턴스 인터페이스의 두 가지 주요 방법이 있습니다.
# 폐쇄형 콜백 방식
$this->app->bind('FooBar', function($app){
새로운 FooBar 반환 ($app['SomethingElse']);
});
# 싱글톤으로 등록하면 후속 호출에서 동일한 인스턴스가 반환됩니다.
$ this->app->singleton('FooBar', function($app){
return new FooBar($app['SomethingElse ']) ;
});
# 기존 인스턴스에 바인딩
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);
컨테이너에서 인스턴스를 해결하는 방법에는 두 가지가 있습니다.
$fooBar = $this-> ;app-> make('FooBar') # make() 메서드를 사용하여
$fooBar = $this->app['FooBar']; # 컨테이너는 ArrayAccess를 구현하기 때문에 인터페이스이므로 배열 액세스 형식을 사용할 수 있습니다
정의한 후 등록 및 구문 분석 정보를 보려면 type-hint를 통해 클래스 생성자에서 필요한 종속성을 직접 지정할 수 있으며 컨테이너는 필요한 모든 종속성을 자동으로 주입합니다. 종속성 .
IlluminateRoutingController 사용;
AppUsersRepository를 UserRepository로 사용;
class UserController 확장 Controller {
protected $users;
공개 함수 __construct(UserRepository $users){ # type-hint
$this->users = $users;
~ 🎜> }
}
바운드 인터페이스
인터페이스
EventPusher{
공개 함수 push($event , array $data); }
클래스 PusherEventPusher
EventPusher
{...}
PusherEventPusher
클래스는EventPusher 인터페이스를 사용하므로 이 인터페이스를 직접 등록하고 이 인터페이스를 구현하는 클래스에 바인딩할 수 있습니다.
$this->app- >bind('AppContractsEventPusher', 'AppServicesPusherEventPusher');
클래스에EventPusher 인터페이스에서는 PusherEventPusher를 삽입해야 한다고 컨테이너에 알립니다.
컨텍스트 바인딩
$this->app->때
('AppHandlersCommandsCreateOrderHandler') —> >주다('AppServicesPubNubEventPusher'); 태그 $this->app->bind('SpeedReport', function(){ }); $this-> app->bind('MemoryReport' , function(){ }); $this->app->tag(['SpeedReport', 'MemoryReport'], 'reports') # 앞의 두 단계에서 등록한 수업을 ' ' 태그에 입력합니다. 서비스에 태그가 지정되면 태그된 메서드를 통해 쉽게 구문 분석할 수 있습니다.
$this-> app->bind('ReportAggregator', function($app){ 새 ReportAggregator( $app->태그됨 ('보고서')); }); 컨테이너 이벤트 컨테이너가 트리거됩니다. 각 객체를 파싱할 때 발생하는 이벤트입니다. resolving
$this->app->resolving(function($object, $app){ # 컨테이너가 모든 유형의 종속성을 해결할 때 호출됩니다 ...}); $this->app->resolving(function(FooBar $fooBar, $app){ # 'FooBar '는 유형의 종속성이
Contracts
Contracts
는 모든 Laravel
주요 구성 요소에서 사용하는 인터페이스입니다. Contracts 디렉토리 구조는
Illuminate와 동일합니다. Contracts는 인터페이스 정의이고 Illuminate는 구체적인 구현입니다. Illuminate에서 구현된 각 구체적 클래스는 Contracts에서 해당 인터페이스를 확장합니다. 이러한 인터페이스와 구현의 분리는 의존성 주입을 덜 결합하게 만들 수 있습니다 . /laravel/framework
/src
/조명
/인증
/방송
/버스
...
/계약서
/인증
/방송중
/버스
...
외관
기본 사용법
Facade
정적 인터페이스 제공은 애플리케이션의 서비스 컨테이너에서 사용할 수 있는
클래스를 제공합니다. (디자인 모드의 "장식 모드" 적용은 주로class_alias를 사용하여 클래스 이름을 생성하고 __callStatic()을 사용하여 궁극적으로 PHP 객체를 시뮬레이션하고 객체의 메서드를 호출하는 정적 프록시) Laravel의 facades 및 사용자가 생성한 모든 사용자 정의 facade는 기본 클래스에서 상속됩니다. 🎜>Facade, getFacadeAccessor() 메소드 하나만 구현하면 됩니다. 예를 들어 캐시이것Facade 호출: $value = 캐시::get('key'); 클래스 구현을 살펴보세요. class 캐시 Facade { 보호 정적 함수 getFacadeAccessor() { return 'cache' } # 이 메소드의 기능은 서비스 컨테이너 바인딩의 이름을 반환하는 것입니다 } 사용자가 Cache의 facade에서 정적 메서드를 실행할 때 Laravel 은 서비스 컨테이너에서 바인딩된 캐시 를 해석하고 요청된 메소드 를 실행합니다. 객체 (이 예에서는 get) 모든 facade는 전역 네임스페이스에 존재합니다. 중첩된 네임스페이스에서 사용되는 경우 facade 클래스를 가져와야 합니다.
캐시 사용 # 가져오기캐시 파사드
클래스 PhotosController 확장 컨트롤러 {
공용 함수 인덱스(){
$photos = Cache::get('photos' ; 🎜>