Difference between revisions of "Basic Laravel Training (for CV)"
								
								Jump to navigation
				Jump to search
				
				
		
					
								
							
		| (30 intermediate revisions by the same user not shown) | |||
| Line 62: | Line 62: | ||
| </syntaxhighlight> | </syntaxhighlight> | ||
| # ลองสร้าง method index | # ลองสร้าง method index | ||
| − | + | #: <syntaxhighlight lang="php" line> | |
| + |     public function index(){ | ||
| + |         $menu = array("Home", "My course", "Setting"); | ||
| + |         return $menu; | ||
| + |     } | ||
| + | </syntaxhighlight> | ||
| + | # เพิ่ม Route ใน <code>routes/web.php</code> | ||
| + | #: <syntaxhighlight lang="php" line> | ||
| + | Route::get('home','page_controller@index'); | ||
| + | </syntaxhighlight> | ||
| + | # ลองทดสอบเรียก url | ||
| + | #: <pre>http://localhost:8000/home</pre> | ||
| + | # ปกติแล้วสิ่งที่ controller คืนมักจะไม่ใช่ array หรือ object ธรรมดา ยกเว้นกรณีที่กำลังเขียน api .. หากเป็นกรณี webpage มักจะคืนเป็น view | ||
| + | # ลองสร้าง view (การสร้าง view จะไม่สามารถเรียกผ่าน artisan ได้ จะต้องสร้างด้วยตัวเอง ใน <code>resources/views</code> โดยให้สร้าง view ชื่อว่า <code>home.blade.php</code> | ||
| + | # ใน controller method index จะเปลี่ยนแปลงการ return ให้ return view แทน | ||
| + | #: <syntaxhighlight lang="php" line> | ||
| + |     public function index(){ | ||
| + |         $menu = array("Home", "My course", "Setting"); | ||
| + |         return view("home")->with('menu',$menu); | ||
| + |     } | ||
| + | </syntaxhighlight> | ||
| + | # ใน <code>home.blade.php</code> ให้ลองเขียน html เพื่อแสดง menu เป็น unordered list | ||
| + | #: <syntaxhighlight lang="html" line> | ||
| + | <!DOCTYPE html> | ||
| + | <html lang="en"> | ||
| + | <head> | ||
| + |     <meta charset="UTF-8"> | ||
| + |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| + |     <meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
| + |     <title>Document</title> | ||
| + | </head> | ||
| + | <body> | ||
| + |     <ul> | ||
| + |         @foreach($menu as $eachmenu) | ||
| + |             <li>{{$eachmenu}}</li> | ||
| + |         @endforeach | ||
| + |     </ul> | ||
| + | </body> | ||
| + | </html> | ||
| + | </syntaxhighlight> | ||
| ==== View (Blade Template) ==== | ==== View (Blade Template) ==== | ||
| + | * <code><meta name="csrf-token" content="{{ csrf_token() }}"></code> | ||
| + | * <code>{{ config('app.name', 'Laravel') }}</code> | ||
| + | * @include('inc.messages') | ||
| + | * @yield('content') | ||
| + | * @extends('layouts.app') | ||
| + | * @section('content')<br>@endsection | ||
| + | * @if | ||
| + | * @for | ||
| + | * @foreach | ||
| + | * @csrf | ||
| + | * {{}} | ||
| + | * {!!  !!} | ||
| === Database === | === Database === | ||
| + | ==== Preparation ==== | ||
| + | * สร้าง database (สมมติว่าชื่อ laravel_training) | ||
| + | * แก้ไข <code>.env</code> | ||
| + | *: <syntaxhighlight> | ||
| + | DB_CONNECTION=mysql | ||
| + | DB_HOST=127.0.0.1 | ||
| + | DB_PORT=3306 | ||
| + | DB_DATABASE=laravel_training | ||
| + | DB_USERNAME=USERNAME | ||
| + | DB_PASSWORD=PASSWORD | ||
| + | </syntaxhighlight> | ||
| + | * แก้ไข file <code>app/Providers/AppServiceProvider.php</code> ข้างบนสุดเพิ่ม | ||
| + | *: <pre>use Illuminate\Support\Facades\Schema;</pre> | ||
| + | * แก้ไข file <code>app/Providers/AppServiceProvider.php</code> function boot เพิ่ม | ||
| + | *: <pre>Schema::defaultStringLength(191);</pre> | ||
| + | * ลอง migrate default script | ||
| + | *: <pre>php artisan migrate</pre> | ||
| + | |||
| ==== Model & DB ==== | ==== Model & DB ==== | ||
| * php artisan make:model MODEL_NAME --migration | * php artisan make:model MODEL_NAME --migration | ||
| * php artisan make:migration MIGRATION_NAME | * php artisan make:migration MIGRATION_NAME | ||
| + | * Sample | ||
| + | *: <!--syntaxhighlight lang="php"> | ||
| + | <?php | ||
| + |     public function up() | ||
| + |     { | ||
| + |         Schema::enableForeignKeyConstraints(); | ||
| + |         Schema::create('cvdrive_comments', function (Blueprint $table) { | ||
| + |             $table->increments('id'); | ||
| + |             $table->text('comment')->nullable($value = true); | ||
| + |             $table->integer('cvdrive_item_id')->unsigned(); | ||
| + |             $table->integer('user_id')->unsigned(); | ||
| + |             $table->integer('cvdrive_comment_id')->unsigned()->nullable($value = true); | ||
| + |             $table->timestamps(); | ||
| + | |||
| + |             $table->foreign('cvdrive_item_id')->references('id')->on('cvdrive_items')->onDelete('cascade'); | ||
| + |             $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); | ||
| + |             $table->foreign('cvdrive_comment_id')->references('id')->on('cvdrive_comments')->onDelete('cascade'); | ||
| + |         }); | ||
| + |     } | ||
| + | |||
| + |     public function down() | ||
| + |     { | ||
| + |         Schema::dropIfExists('cvdrive_comments'); | ||
| + |     } | ||
| + | } | ||
| + | |||
| + | </syntaxhighlight--> | ||
| ==== Eloquent ==== | ==== Eloquent ==== | ||
| + | * php artisan tinker | ||
| + | * new item | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | $course = new course(); | ||
| + | $course->number = "2110221"; | ||
| + | $course->title = "Computer Engineering Essentials"; | ||
| + | $course->year = 2018; | ||
| + | $course->semester = 2; | ||
| + | $course->save(); | ||
| + | </syntaxhighlight> | ||
| + | * duplicate item : $newcourse2 = $newcourse->replicate(); | ||
| + | * fetch item | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | $allcourses = course::all(); | ||
| + | $findcourse = course::find(1); | ||
| + | $findcourse = course::where(number,"2110221")->get(); | ||
| + | |||
| + | // ->where("title","like","%".$keyword."%") | ||
| + | // ->orderBy('created_at','desc') | ||
| + | // ->paginate(10); | ||
| + | // In view show page numbers: {{$items->links()}} | ||
| + | </syntaxhighlight> | ||
| + | * edit item | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | $course = course::find(1); | ||
| + | $course->title = "NEW NAME"; | ||
| + | $course->save(); | ||
| + | </syntaxhighlight> | ||
| + | * delete item | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | $course = course::find(1); | ||
| + | $course->delete(); | ||
| + | </syntaxhighlight> | ||
| ==== Handle CRUD ==== | ==== Handle CRUD ==== | ||
| Line 76: | Line 205: | ||
| * method: get, post, patch, delete | * method: get, post, patch, delete | ||
| * Route::resource('ROUTE', 'CONTROLLER'); | * Route::resource('ROUTE', 'CONTROLLER'); | ||
| + | * php artisan route:list | ||
| + | * Handle request | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | $name = $request->input('name', 'Default');  | ||
| + | $name = $request->name; | ||
| + | </syntaxhighlight> | ||
| + | * Validation --> [https://laravel.com/docs/5.8/validation See Doc] | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | $request->validate([ | ||
| + |     'title' => 'required|max:255', | ||
| + |     'body' => 'required', | ||
| + | ]); | ||
| + | |||
| + | // Frontend display error | ||
| + | @if ($errors->any()) | ||
| + |     <div class="alert alert-danger"> | ||
| + |         <ul> | ||
| + |             @foreach ($errors->all() as $error) | ||
| + |                 <li>{{ $error }}</li> | ||
| + |             @endforeach | ||
| + |         </ul> | ||
| + |     </div> | ||
| + | @endif | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | ==== Relationship ==== | ||
| + | ===== one to one ===== | ||
| + | * Defining relationship | ||
| + | *: return $this->hasOne('App\Phone', 'foreign_key', 'local_key'); | ||
| + | * Defining inverse relationship | ||
| + | *: return $this->belongsTo('App\User', 'foreign_key', 'other_key'); | ||
| + | |||
| + | ===== one to many ===== | ||
| + | * Defining relationship | ||
| + | *: return $this->hasMany('App\Comment', 'foreign_key', 'local_key'); | ||
| + | * Defining inverse relationship | ||
| + | *: return $this->belongsTo('App\Post', 'foreign_key', 'other_key'); | ||
| + | |||
| + | ===== many to many ===== | ||
| + | * Defining relationship | ||
| + | *: return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id'); | ||
| + | *: return $this->belongsToMany('Model','Intermediate table name','fk of current model','fk of another model') | ||
| + | * Defining inverse relationship | ||
| + | *: return $this->belongsToMany('App\User', 'role_user', 'role_id', 'user_id'); | ||
| + | *: return $this->belongsToMany('Model','Intermediate table name','fk of current model','fk of another model') | ||
| === Authentication === | === Authentication === | ||
| + | ==== Preparation ==== | ||
| + | * php artisan make:auth | ||
| + | |||
| ==== User System ==== | ==== User System ==== | ||
| + | * $user = Auth::user(); | ||
| + | * $id = Auth::id(); | ||
| + | * Protect route | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | // Protect in route | ||
| + | Route::get('index','homecontroller@index')->middleware('auth'); | ||
| + | |||
| + | // Protect in constructor | ||
| + | public __construct{ | ||
| + |     $this->middleware('auth', ['except' => ['getActivate', 'anotherMethod']]); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | * Check if the user is loggedin | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | if (Auth::check()) { | ||
| + |     // The user is logged in... | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| ==== Access Control ==== | ==== Access Control ==== | ||
| + | * Using Policy | ||
| + | * php artisan make:policy POLICY_NAME | ||
| + | * php artisan make:policy POLICY_NAME --model=MODEL // Create with basic CRUD | ||
| + | * Register Policy in <code>App/Providers/Authserviceprovider.php</code> | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + |     protected $policies = [ | ||
| + |         Post::class => PostPolicy::class, | ||
| + |     ]; | ||
| + | </syntaxhighlight> | ||
| + | * Writing Policy | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | public function update(User $user, Post $post){ | ||
| + |     return $user->id === $post->user_id; | ||
| + | } | ||
| + | |||
| + | // Check Policy | ||
| + | if ($user->can('update', $post)) { | ||
| + |     // | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | * Writing Policy without model | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | public function create(User $user){ | ||
| + |     // | ||
| + | } | ||
| + | |||
| + | // Check Policy | ||
| + | if ($user->can('create', Post::class)) { // ต้องบอก class เพื่อจะได้รู้ว่าจะไปเรียกจาก policy ของ class ไหน | ||
| + |     //  | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | * Writing Policy in View | ||
| + | *: <syntaxhighlight lang="php"> | ||
| + | @can('update', $post) | ||
| + |     <!-- The Current User Can Update The Post --> | ||
| + | @elsecan('create', App\Post::class) | ||
| + |     <!-- The Current User Can Create New Post --> | ||
| + | @endcan | ||
| + | |||
| + | |||
| + | @if (Auth::user()->can('update', $post)) | ||
| + |     <!-- The Current User Can Update The Post --> | ||
| + | @endif | ||
| + | |||
| + | |||
| + | @unless (Auth::user()->can('update', $post)) | ||
| + |     <!-- The Current User Can't Update The Post --> | ||
| + | @endunless | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | == Testing == | ||
| + | * Make test <syntaxhighlight> | ||
| + | // Create a test in the tests/Feature directory... | ||
| + | php artisan make:test UserTest | ||
| + | |||
| + | // Create a test in the tests/Unit directory... | ||
| + | php artisan make:test UserTest --unit | ||
| + | </syntaxhighlight> | ||
| + | * Run test : In your project root run <pre>vendor/bin/phpunit</pre> | ||
| + | * The CSRF middleware is automatically disabled when running tests | ||
| + | * Use model factory to generate fake object | ||
| + | ** Factory is at <code> database/factories/UserFactory.php</code> | ||
| + | ** In testing <syntaxhighlight lang="php"> | ||
| + | $user = factory(User::class)->create(); | ||
| + | $response = $this->actingAs($user)->withSession(['foo' => 'bar'])->get('/'); | ||
| + | </syntaxhighlight> | ||
| + | * Browser Test [[https://laravel.com/docs/5.8/dusk https://laravel.com/docs/5.8/dusk]] | ||
| + | * And more ... in Laravel Doc | ||
| + | |||
| + | == More and More == | ||
| + | === Middleware === | ||
| + | * อยู่ระหว่าง routing กับ controller  | ||
| + | ** มีอยู่แล้วคือ Auth | ||
| + | ** อาจมีอื่นๆ เช่น CORS middleware, Log middleware | ||
| + | * การสร้าง Middleware | ||
| + | ** <code>php artisan make:middleware CheckAge</code> | ||
| + | ** File จะอยู่ที่ <code> app/Http/Middleware</code> | ||
| + | ** ตัวอย่างนี้ เป็น middleware ที่เช็ค age  | ||
| + | *** ถ้า age <= 200 จะไม่อนุญาตให้ไปต่อ โดยจะ redirect ไปที่ home | ||
| + | *** ถ้า age > 200 จะไปต่อ โดยเรียก $next($request) $next คือ function ที่มันควรจะเข้าจริงๆ | ||
| + | ** <syntaxhighlight lang="php"> | ||
| + | <?php | ||
| + | |||
| + | namespace App\Http\Middleware; | ||
| + | |||
| + | use Closure; | ||
| + | |||
| + | class CheckAge | ||
| + | { | ||
| + |     /** | ||
| + |      * Handle an incoming request. | ||
| + |      * | ||
| + |      * @param  \Illuminate\Http\Request  $request | ||
| + |      * @param  \Closure  $next | ||
| + |      * @return mixed | ||
| + |      */ | ||
| + |     public function handle($request, Closure $next) | ||
| + |     { | ||
| + |         if ($request->age <= 200) { | ||
| + |             return redirect('home'); | ||
| + |         } | ||
| + | |||
| + |         return $next($request); | ||
| + |     } | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | ** Middleware อาจจะทำก่อน หริือ หลัง request ก็ได้  | ||
| + | *** ทำก่อน (ตัวอย่างกรณีข้างบน) | ||
| + | *** ทำหลัง <syntaxhighlight lang="php"> | ||
| + |     public function handle($request, Closure $next) | ||
| + |     { | ||
| + |         $response = $next($request); | ||
| + | |||
| + |         // Perform action | ||
| + | |||
| + |         return $response; | ||
| + |     } | ||
| + | </syntaxhighlight> | ||
| + | * หลังจากสร้างแล้ว จะต้องเอาไป register ไว้ที่ <code> app/Http/Kernel.php</code> | ||
| + | * การนำไปใช้ | ||
| + | ** จะเอาไปผูกกับ route <syntaxhighlight lang="php"> | ||
| + | Route::get('admin/profile', function () { | ||
| + |     // | ||
| + | })->middleware('auth', 'second_middleware'); | ||
| + | </syntaxhighlight> | ||
| + | * Middleware group (Assign ทีเดียวหลายตัวเป็น group) | ||
| + | * Middleware parameters | ||
| + | ** ตัวอย่างการเช็ค role <syntaxhighlight lang="php"> | ||
| + | <?php | ||
| + | |||
| + | namespace App\Http\Middleware; | ||
| + | |||
| + | use Closure; | ||
| + | |||
| + | class CheckRole | ||
| + | { | ||
| + |     /** | ||
| + |      * Handle the incoming request. | ||
| + |      * | ||
| + |      * @param  \Illuminate\Http\Request  $request | ||
| + |      * @param  \Closure  $next | ||
| + |      * @param  string  $role | ||
| + |      * @return mixed | ||
| + |      */ | ||
| + |     public function handle($request, Closure $next, $role) | ||
| + |     { | ||
| + |         if (! $request->user()->hasRole($role)) { | ||
| + |             // Redirect... | ||
| + |         } | ||
| + | |||
| + |         return $next($request); | ||
| + |     } | ||
| + | |||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | ** การนำไปใช้ กรณีนี้จะตรวจสอบว่า route นี้จะเข้าได้เฉพาะคนที่มี role เป็น editor เท่านั้น <syntaxhighlight lang="php"> | ||
| + | Route::put('post/{id}', function ($id) { | ||
| + |     // | ||
| + | })->middleware('role:editor'); | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | === OAUTH === | ||
| + | * [[https://laravel.com/docs/5.8/passport Laravel Passport (Library for OAUTH Server)]] | ||
| + | |||
| + | == More References == | ||
| + | * [[https://github.com/alexeymezenin/laravel-best-practices#follow-laravel-naming-conventions Laravel Best Practices]] | ||
Latest revision as of 00:13, 26 April 2019
Contents
Reference
- Laravel Documentation
https://laravel.com/docs/5.8
Installation
Requirements
- PHP >= 7.1.3
- OpenSSL PHP Extension
- PDO PHP Extension
- Mbstring PHP Extension
- Tokenizer PHP Extension
- XML PHP Extension
- Ctype PHP Extension
- JSON PHP Extension
- BCMath PHP Extension
Steps
- Install LAMP Stack (ie. XAMPP) อย่าลืมจำ mysql root password!!
- Install Composer
- https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos
- หมายเหตุ: เวลาเรียกใช้งาน composer อาจจะต้องใช้ ./composer.pharแทนที่composerถ้าทำการ Install composer เป็น local
 
- สร้าง Laravel Project โดยใช้ composer
- composer create-project --prefer-dist laravel/laravel PROJECT_NAME 
 
- Run Local Development Server
- php artisan serve # for running on localhost:8000 
- or
- php artisan serve --port=8888 # for running on localhost:8888 
 
Basic Tutorial
Important directory / file
- appWhere the models are- Http- Controllers
- Middleware
 
 
- config
- database
- publicWhere the public files (ie. css, js)
- resources- views
 
- routes- api.php
- web.php
 
- vendorWhere the additional libraries store
- .envall environment variables (ie. DB username/password)
Intro
Controller & Route
- Let's make a controller: page_controller
- php artisan make:controller CONTROLLER_NAME 
- จะมีไฟล์ app/Http/Controllers/page_controller.phpปรากฎ
 
- ในไฟล์จะมี code เหล่านี้
- 1 <?php 2 3 namespace App\Http\Controllers; 4 5 use Illuminate\Http\Request; 6 7 class page_controller extends Controller 8 { 9 // 10 } 
 
- ลองสร้าง method index
- 1 public function index(){ 2 $menu = array("Home", "My course", "Setting"); 3 return $menu; 4 } 
 
- เพิ่ม Route ใน routes/web.php- 1 Route::get('home','page_controller@index'); 
 
- ลองทดสอบเรียก url
- http://localhost:8000/home 
 
- ปกติแล้วสิ่งที่ controller คืนมักจะไม่ใช่ array หรือ object ธรรมดา ยกเว้นกรณีที่กำลังเขียน api .. หากเป็นกรณี webpage มักจะคืนเป็น view
- ลองสร้าง view (การสร้าง view จะไม่สามารถเรียกผ่าน artisan ได้ จะต้องสร้างด้วยตัวเอง ใน resources/viewsโดยให้สร้าง view ชื่อว่าhome.blade.php
- ใน controller method index จะเปลี่ยนแปลงการ return ให้ return view แทน
- 1 public function index(){ 2 $menu = array("Home", "My course", "Setting"); 3 return view("home")->with('menu',$menu); 4 } 
 
- ใน home.blade.phpให้ลองเขียน html เพื่อแสดง menu เป็น unordered list- 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <ul> 11 @foreach($menu as $eachmenu) 12 <li>{{$eachmenu}}</li> 13 @endforeach 14 </ul> 15 </body> 16 </html> 
 
View (Blade Template)
- <meta name="csrf-token" content="Template:Csrf token()">
- Template:Config('app.name', 'Laravel')
- @include('inc.messages')
- @yield('content')
- @extends('layouts.app')
- @section('content')
 @endsection
- @if
- @for
- @foreach
- @csrf
- {{}}
- {!! !!}
Database
Preparation
- สร้าง database (สมมติว่าชื่อ laravel_training)
- แก้ไข .env- DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_training DB_USERNAME=USERNAME DB_PASSWORD=PASSWORD 
 
- แก้ไข file app/Providers/AppServiceProvider.phpข้างบนสุดเพิ่ม- use Illuminate\Support\Facades\Schema; 
 
- แก้ไข file app/Providers/AppServiceProvider.phpfunction boot เพิ่ม- Schema::defaultStringLength(191); 
 
- ลอง migrate default script
- php artisan migrate 
 
Model & DB
- php artisan make:model MODEL_NAME --migration
- php artisan make:migration MIGRATION_NAME
- Sample
Eloquent
- php artisan tinker
- new item
- $course = new course(); $course->number = "2110221"; $course->title = "Computer Engineering Essentials"; $course->year = 2018; $course->semester = 2; $course->save(); 
 
- duplicate item : $newcourse2 = $newcourse->replicate();
- fetch item
- $allcourses = course::all(); $findcourse = course::find(1); $findcourse = course::where(number,"2110221")->get(); // ->where("title","like","%".$keyword."%") // ->orderBy('created_at','desc') // ->paginate(10); // In view show page numbers: {{$items->links()}} 
 
- edit item
- $course = course::find(1); $course->title = "NEW NAME"; $course->save(); 
 
- delete item
- $course = course::find(1); $course->delete(); 
 
Handle CRUD
- php artisan make:controller CONTROLLER_NAME --resource
- method: get, post, patch, delete
- Route::resource('ROUTE', 'CONTROLLER');
- php artisan route:list
- Handle request
- $name = $request->input('name', 'Default'); $name = $request->name; 
 
- Validation --> See Doc
- $request->validate([ 'title' => 'required|max:255', 'body' => 'required', ]); // Frontend display error @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif 
 
Relationship
one to one
- Defining relationship
- return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
 
- Defining inverse relationship
- return $this->belongsTo('App\User', 'foreign_key', 'other_key');
 
one to many
- Defining relationship
- return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
 
- Defining inverse relationship
- return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
 
many to many
- Defining relationship
- return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
- return $this->belongsToMany('Model','Intermediate table name','fk of current model','fk of another model')
 
- Defining inverse relationship
- return $this->belongsToMany('App\User', 'role_user', 'role_id', 'user_id');
- return $this->belongsToMany('Model','Intermediate table name','fk of current model','fk of another model')
 
Authentication
Preparation
- php artisan make:auth
User System
- $user = Auth::user();
- $id = Auth::id();
- Protect route
- // Protect in route Route::get('index','homecontroller@index')->middleware('auth'); // Protect in constructor public __construct{ $this->middleware('auth', ['except' => ['getActivate', 'anotherMethod']]); } 
 
- Check if the user is loggedin
- if (Auth::check()) { // The user is logged in... } 
 
Access Control
- Using Policy
- php artisan make:policy POLICY_NAME
- php artisan make:policy POLICY_NAME --model=MODEL // Create with basic CRUD
- Register Policy in App/Providers/Authserviceprovider.php- protected $policies = [ Post::class => PostPolicy::class, ]; 
 
- Writing Policy
- public function update(User $user, Post $post){ return $user->id === $post->user_id; } // Check Policy if ($user->can('update', $post)) { // } 
 
- Writing Policy without model
- public function create(User $user){ // } // Check Policy if ($user->can('create', Post::class)) { // ต้องบอก class เพื่อจะได้รู้ว่าจะไปเรียกจาก policy ของ class ไหน // } 
 
- Writing Policy in View
- @can('update', $post) <!-- The Current User Can Update The Post --> @elsecan('create', App\Post::class) <!-- The Current User Can Create New Post --> @endcan @if (Auth::user()->can('update', $post)) <!-- The Current User Can Update The Post --> @endif @unless (Auth::user()->can('update', $post)) <!-- The Current User Can't Update The Post --> @endunless 
 
Testing
- Make test // Create a test in the tests/Feature directory... php artisan make:test UserTest // Create a test in the tests/Unit directory... php artisan make:test UserTest --unit 
- Run test : In your project root run vendor/bin/phpunit 
- The CSRF middleware is automatically disabled when running tests
- Use model factory to generate fake object
- Factory is at database/factories/UserFactory.php
- In testing $user = factory(User::class)->create(); $response = $this->actingAs($user)->withSession(['foo' => 'bar'])->get('/'); 
 
- Factory is at 
- Browser Test [https://laravel.com/docs/5.8/dusk]
- And more ... in Laravel Doc
More and More
Middleware
- อยู่ระหว่าง routing กับ controller
- มีอยู่แล้วคือ Auth
- อาจมีอื่นๆ เช่น CORS middleware, Log middleware
 
- การสร้าง Middleware
- php artisan make:middleware CheckAge
- File จะอยู่ที่ app/Http/Middleware
- ตัวอย่างนี้ เป็น middleware ที่เช็ค age
- ถ้า age <= 200 จะไม่อนุญาตให้ไปต่อ โดยจะ redirect ไปที่ home
- ถ้า age > 200 จะไปต่อ โดยเรียก $next($request) $next คือ function ที่มันควรจะเข้าจริงๆ
 
- <?php namespace App\Http\Middleware; use Closure; class CheckAge { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if ($request->age <= 200) { return redirect('home'); } return $next($request); } } 
- Middleware อาจจะทำก่อน หริือ หลัง request ก็ได้
- ทำก่อน (ตัวอย่างกรณีข้างบน)
- ทำหลัง public function handle($request, Closure $next) { $response = $next($request); // Perform action return $response; } 
 
 
- หลังจากสร้างแล้ว จะต้องเอาไป register ไว้ที่ app/Http/Kernel.php
- การนำไปใช้
- จะเอาไปผูกกับ route Route::get('admin/profile', function () { // })->middleware('auth', 'second_middleware'); 
 
- จะเอาไปผูกกับ route 
- Middleware group (Assign ทีเดียวหลายตัวเป็น group)
- Middleware parameters
- ตัวอย่างการเช็ค role <?php namespace App\Http\Middleware; use Closure; class CheckRole { /** * Handle the incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param string $role * @return mixed */ public function handle($request, Closure $next, $role) { if (! $request->user()->hasRole($role)) { // Redirect... } return $next($request); } } 
- การนำไปใช้ กรณีนี้จะตรวจสอบว่า route นี้จะเข้าได้เฉพาะคนที่มี role เป็น editor เท่านั้น Route::put('post/{id}', function ($id) { // })->middleware('role:editor'); 
 
- ตัวอย่างการเช็ค role 
