Laravel
===
###### tags: `PHP` `Laravel` `artisan` `全端`
# 雜記
- composer create-project laravel/laravel pjname --prefer-dist
- Laravel Engine: Blade
- PSR-4
PHP-FIG 建議規範
- 讓使用者輸入錯誤後不用重新輸入一次
{{ old('name', 'default') }}
# Laravel 資料夾結構
## resources
靜態的東西都在這
### views
此資料夾內放置主要畫面樣板
只要副檔名 blade.php 的東西
就會用 blade engine 解析
再丟進 php interpreter
## routes
路徑的管理
### web.php
用 GET POST 等 method 以及 URL 來做網頁導向
- 基本使用方式
e.g.
```php=
Route::get('/user/{name?}', function($name = 'Nobody') {
return 'Hi, '.strtoupper($name);
});
```
假設使用者 Get URL /user/Ljp
會回傳 'Hi, LJP'
假設使用者 Get URL /user
會回傳 'Hi, NOBODY'
Route::get 的第一個參數中的 \{\} 表示這是 URL 中的參數
它會傳給 Route::get 中第二個參數的 function
若 \{\} 尾巴有一個 '?' 表示此參數可有可無
- 配合 Controller
- web.php
```php
Route::get('/', 'HomeController@index');
```
- HomeController.php
```php
class HomeController extends Controller
{
public function index () {
return view('welcome');
}
}
```
這個意思是將 URL '/' 導向到 HomeController 中的 index function
- 幫 Route 取名
取名字後, 在要用到 `{{ route(...) }}`的時候可以直接用這個名字就好, 不用整個路徑打出來
- web.php
```php
Route::get('/', 'HomeController@index')->name('home.index');
```
- edit.blade.php
```php
...
<a href="{{ route('home.index') }}">test</a>
...
```
# Routing
## Controller
```shell
artisan make:controller NameOfController
```
若加上參數 --resource
會創造已經寫好
- index()
- create()
- store()
- show()
- edit()
- update()
- destroy()
的 Controller
## 設定 route
在 route/web.php 設定
語法大致上為
```php
<?php
Route::method('url', 'Controller@function')->name('在其他 html 中, 連結的別名');
```
e.g.
```php
<?php
Route::get('products', 'ProductController@index')->name('products.index');
```
# Laravel With DB
## database.php & .env
- 先創好 database
- 設定檔案
- 在 database.php 中 env(...) 都是去 .env 找參數
設定好後, 敲下指令
```shell
artisan migrate:install
```
用你現在的設定檔, 連上資料庫後, 在資料庫建立資料表 migration, 用來測試是否連得上
## migration
### 產生
```shell
artisan make:migration {action}_{table}_table
artisan make:migration create_products_table
```
此指令會在 database migrations 中產生新的 migration
### 執行資料庫變更
寫完 migration 後, 要執行
```shell
artisan migrate
```
資料庫變更才會真的被套用
用爛了就
```shell
artisan migrate:rollback
```
## Model
參考: https://laravel.com/docs/5.7/eloquent
跟資料庫讀寫有關的動作, 可透過Model類別來操作
所以 check 好已經連動到資料庫, 就可以實作 Model 來與程式碼連動
```shell
artisan make:model {name}
artisan make:model Task
```
之後設定 `$table` 來設定此 Model 跟哪張 table 連動
```php
<?php
...
class Product extends Model
{
protected $table = 'products';
protected $fillable = [
'Blablabal',
'abcabc'
];
}
```
### 方法
- create()
- update()
- ModelName::orderBy()
- get()
- save()
f
## Seeding
定義用 artisan 執行 db 時會如何操作資料庫
### 用 artisan 產生 seeder 檔案
```shell
artisan make:seeder ProductsTableSeeder
```
### 撰寫 seeder 檔案內容
用建立一個紀錄來作例子, ProductsTableSeeder.php:
```php
<?php
...
class ProductsTableSeeder extends Seeder
{
...
public function run()
{
Product::create([
'name' => 'Ming',
'price' => '87'
]);
}
}
```
### 設定 DatabaseSeeder.php 的執行緒
database/seeds/DatabaseSeeder.php:
```php
<?php
...
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call(ProductsTableSeeder::class);
}
}
```
### 用 artisan 執行 db
```shell
artisan db:seed
```
## 應用
若
`web.php` route 中設定的變數 跟 `controller` 裡的 function parameter 設定一樣
且
`controller` parameter 有給他 `model` class
那
去那 `model` 代表的 table, 用此 parameter 當 primary key 去撈資料
## Relationship
兩個 model 都要先定義彼此的關係
- Product.php
```php=
<?php
...
public function category()
{
return $this->belongsTo(Category::class, 'category_id', 'id');
}
...
```
- Category.php
```php=
<?php
...
public function products() {
return $this->hasMany(Product::class, 'category_id');
}
...
```
建立關係語法:
[`自己之於對方的關係`](`要建立關係的 Table`, `自己要綁定的 foreign key`, `要綁定對方的 foreign key`)
https://laravel.com/docs/5.7/eloquent-relationships#querying-relations
# Git 問題
## composer
就像 npm 之於 Node.js
composer 是 php 的模組管理套件
## 合作問題
pull 別人的專案下來後, 因為 .gitignore 的關係
會缺一點東西
以下指令把需要的補回來
### /vendor
補回 /vendor
```shell
composer install
```
### .env
執行設定於 composer.json 中的腳本
產生 .env
```shell
composer run-script post-root-package-install
```
### app key
產生 app key
```shell
composer run-script post-create-project-cmd
```
# Validation
分三類
- Validation Facade
- Controller Validation
- Form Request Validation
## Controller Validation
Controller 本身有 validate 這個方法
格式像是
xxxxController.php
```php
<?php
...
public function test()
{
...
$this->validate(要檢驗物件, 規則, 錯誤訊息);
...
}
...
```
實際例子, 請看`參考4`
```php
<?php
$rule = [
'name' => 'required',
'price' => 'required',
'unit' => 'required',
'description' => 'required'
];
$messages = [
'name.required' => '名字沒寫QQ'
];
$this->validate($request, $rule, $messages);
```
在 laravel 的 views 中自動有加 MessageBag $errors 參數
顯示在 html 上請看`參考2`
參考:
1. https://laravel.com/docs/5.7/validation#available-validation-rules
2. https://laravel.com/docs/5.7/validation#quick-displaying-the-validation-errors
3. https://laravel.com/docs/5.7/validation#custom-error-messages
4. https://stackoverflow.com/questions/45007905/custom-message-laravel-validation
# Auth
安裝, 會自動跑出登入登出忘記密碼三小的 view, 並自動把 route 寫好
```shell
artisan make:auth
```
在 route 中可以這樣保護 URL
```php=
<?php
...
Route::middleware('auth')->group(function () {
Route::get('/', 'DashboardController@index')->name('dashboard.index');
Route::get('/products', 'ProductController@index')->name('products.index');
Route::get('/products/create', 'ProductController@create')->name('products.create');
Route::post('/products', 'ProductController@store')->name('products.store');
Route::get('/products/{product}/edit', 'ProductController@edit')->name('products.edit');
Route::patch('/products/{product}', 'ProductController@update')->name('products.update');
Route::delete('/products/{product}', 'ProductController@delete')->name('products.destroy');
});
...
```
也可以
```php=
<?php
Route::get('/', 'DashboardController@index')->name('dashboard.index')->middleware('auth');
```
# API
## Html 狀態碼
https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status
## api.php
若是用網頁互動, route 是設定在 web.php
而 api 則是在 api.php
差別在於 middleware
kernel.php 設定更多
## controller
```php
<?php
...
public function index()
{
$products = Product::all();
return response()->json($products);
}
```
之後 URL 打 api/...
就可以看到 json 編碼過後的 products
**Chrome 套件**
- json formatter
## CORS(Cross-Origin Resource Sharing)
如何讓API可以正確地被跨網域呼叫?
設定 Header
**套件**
https://github.com/spatie/laravel-cors#laravel
## Resource
```shell
artisan make:resource ProductResource
```
原先 controller 從資料庫撈到資料後就直接丟出去
可是一來欄位洩漏出去, 二來有時候也不用全丟
這時就可以用 Resource 來定義要丟出去的資源
## Auth
### 安裝套件
https://jwt-auth.readthedocs.io/en/develop/laravel-installation/
```shell
composer require tymon/jwt-auth:1.0.0-rc.3
artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
```
### 設定 User Model
https://jwt-auth.readthedocs.io/en/develop/quick-start/#update-your-user-model
### 設定 config/auth.php
https://jwt-auth.readthedocs.io/en/develop/quick-start/#configure-auth-guard
### 保護 API
- api.php
```php
<?php
...
Route::middleware('auth:api')->group(function () {
Route::post('orders', 'Api\OrderController@store');
Route::post('logout', 'Api\AuthController@logout');
});
...
```
### Controller
https://jwt-auth.readthedocs.io/en/develop/quick-start/#create-the-authcontroller
AppDataService
NoWrapping