# Laravel筆記
## 套件管理 Composer or Laravel Installer
1. 使用composer -> 到官網下載:https://getcomposer.org/ ,然後執行並安裝,到某一步驟時將add to PATH 選項勾選用以自動加入環境變數。
2. 使用Laravel Installer -> 到terminal中鍵入指令
```terminal
composer global require "laravel/installer"
```
## 建立新專案:
```php=
composer create-project --prefer-dist laravel/laravel (專案名稱)
laravel new (專案名稱)
```
## 運行網頁(啟用網頁伺服器)
```terminal
php artisan server
```
## 專案結構
### (一)設定檔config資料夾 設定整個專案的 Web APP
1. database.php -> 設定與資料庫連線,有各種DB引擎adapter
2. mail.php -> 寄信用 (等同於PHP Mailer)
### (二)database資料夾
1. 放置與資料庫相關之目錄與文件
2. 底下的migrations資料夾很重要,尤其是多人開發,會記錄資料庫變化
### (三)public資料夾
1. 放置一些公開的東西
2. htaceess 設定權限
### (四)resources資料夾
1. 網站開發所需資源存放處
2. views資料夾存放頁面
### (五)routes資料夾
1. 控制各個網站進入點
2. web.php 控制主要進入點
3. api.php 可以寫api的地方(想提供的api)
### (六)vendor資料夾
1. 放置套件的地方,跟著整個專案一起佈署
2.
### (七).env檔
環境設定檔,設定一些較機密的資料,如資料庫密碼、AWS存取金鑰、PUSHER_APP推播用的東西、smtp等等
### (八).gitignore檔
裡面的東西不會被push上去gitghub上,如有東西不要丟上去git可以放裡面
### (九)composer.json檔
放置整個專案所有套件的版本資訊
### (十)package.json檔
前端套件版本資訊
## 虛擬環境
1. Laravel Homestead
2. Docker
## 設定路由、視圖函數 = Python-Django -> url.py、views.py
專案底下的routes資料夾下web.php
## 目標網頁 = Python-Django->template資料夾
專案底下的resources資料夾的views資料夾的任一檔案
## 當目標檔名相同,優先使用public資料夾的東西,public資料夾 > views資料夾 > 其他資料夾
## 套用佈景(layouts "須自己建")
@extends('layout.app') -> 套用resources資料夾底下的layout資料夾底下的app.blade.php
## Models資料夾 -> (projectname/app/Models)
## Views資料夾 -> (projectname/resources/views)
## Controllers資料夾 -> (projectname/app/Http/Controllers/)
## 路徑說明
### 1. 一般情況不帶參數傳遞時
```php=
// 雙冒號後面是填寫適當的http請求動作
// get、post
Route::get('/', function () { // 控制進入路徑,可控制使用者使用甚麼網址進入網頁
return view('welcome'); // 回傳甚麼畫面給使用者看
});
```
### 2. 帶參數傳遞時,如id(可帶多個參數)
```php=
// 小括號放參數存放的變數以供function解析
Route::get('/cats/{id}',function($id){ // 路徑內部須帶大括號,以供參數傳遞
return "我是第" . $id . "個人";
});
```
### 3. 連結指定Controller
```php=
// 逗點後接陣列,[Controllername::class, 'functionname']
Route::get('/about', [WelcomeController::class ,'about']);
```
### 4. 開放部分網址(URL入口管理)
```php=
// 只開放index、show
Route::resource('posts', PostController::class) -> only(['index', 'show']);
// 除了index、show以外都開放
Route::resource('posts', PostController::class) -> except(['index', 'show']);
```
## Controller寫法
```php=
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class WelcomeController extends Controller
{
//
public function about(){
return view('about');
//return view('pages/about') // 當有第二層資料夾時(view/pages/about)
//return view('pages.about') // 效果同上,如果使用這種寫法,避免再路徑上的資料夾加上'.',否則容易出錯
}
}
```
## HTTP動詞(設定路由時可以用到)
1. get 索取一or多筆資料
2. post 新增一or多筆資料
3. patch(部分)/put(全部) 修改資料
4. delete 刪除一or多筆資料
5. any 所有動作我都處理
6. match 符合相應動作的才處理網頁請求(可用陣列儲存你允許的動作)
## 查看 php artisan 底下有什麼功能~~
### EX:查看artisan有什麼功能
```terminal
php artisan
```
### EX:啟用網頁伺服器
```terminal
php artisan serve
```
### EX:網站維護模式與取消
```terminal=
1. 開啟維護模式-開後門
# 開啟維護模式,後面參數可彈性使用,在這邊是開一個秘密端口給工程師使用
# 可觀察cookie,會發現,多一個通行證
php artisan down --secret=hello
2. 開啟維護模式-指定路徑顯示維護中畫面(需創建一個notok.blade.php的檔案)
php artisan down --render='notok'
3. 關閉維護模式
php artisan up # 關閉維護模式
```
### EX:新增Controller
#### (後面如果加 - -resource會自動加入一些常用function框架)
```terminal
php artisan make:controller NameController --resource
```
### EX:新增Model
#### (後面如果加上 - - migration 或是 -m 有順便加上migration動作的意思)
#### (這樣方便也比較不會有model跟table勾稽上有問題)
```terminal
php artisan make:model modName --migration
```
### EX:查看有什麼Route
```terminal
php artisan route:list
```
### EX:建立資料庫描述檔(Laravel也是採用ORM)=>Eloquent ORM
#### create_posts_table(檔名) - -create="posts"(新增一個叫做posts的資料表)
```terminal
php artisan make:migration create_posts_table --create="posts"
```
### EX:遷移(同步)資料庫or退回前版本
#### migrate是負責資料表結構而不是內容
**執行有風險,如果已有資料存在,rollback後資料會連帶資料表一起消失**
```terminal=
# 執行遷移動作
php artisan migrate
# 執行退回前一版本動作
php artisan migrate:rollback
# 查看所有migrate狀態
php artisan migrate:status
```
### EX:透過migrate工具生成描述檔處理指定資料表(以處理上面posts表為例)
##### 可以在描述檔名上加一些關鍵字眼(add_...to_tableName),Laravel會自動判別你想操作哪個資料表
```terminal
php artisan make:migration update_posts_table --table="posts"
```
### EX:進入tinker對model進行操作
```terminal
php artisan tinker
```
## tinker
#### 簡單來說,前面通常是寫查詢(挑選條件),後面接你指定的動作,即可完成CRUD
### tinker 操作(C,create)
1. 單欄寫入

2. 多欄寫入(要先進去model覆寫)
```php=
# 對Book的model進行覆寫,類似白名單的用途
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
use HasFactory;
protected $fillable = [ // 開放可多欄寫入的欄位
'title',
'description',
'price',
'available'
];
}
```

### tinker操作(R,read)
1. 簡單查詢

2. 進階查詢
尋找特定字串

指定排序方式

### tinker操作(U,update & D,delete)
1. 更新
(方法一)改值

(方法二)重新填值

(方法三)單次大量修改欄位值

2. 刪除
(方法一)利用id找到該筆資料並全部刪除

(方法二)同上

### 操作model
```terminal=
1. 多欄寫入
$data=['fieldName'='value',...]
Book::create($data)
2. 單欄寫入
$b = new Book
$b -> 'fieldName1'='value1';
$b -> 'fieldName2'='value2';
$b -> 'fieldName3'='value3';
$b -> save();
3. 計算該model內有幾筆資料
Book::count()
4. 利用id尋找特定筆資料
Book::find(1) // 尋找id=1的資料
Book::findOrFail(1) // 跟上面一樣,但如果查不到該筆資料會顯示錯誤訊息,而不是null
5. 利用資料欄位值尋找特定資料(如果加上->get()表示不繼續串接query,進行查詢)
Book::where('fieldName','value')->get()
6. 上一個的進階查詢(包含特定字串,%的用法同SQL,放的位置不同,效果也不同)
Book::where('fieldName','like','value%')->get()
7. orderBy(),以大到小為例
Book::where('fieldName','like','value%')->orderBy('id', 'sortMode')->get()
8. 其他操作,如:加法,平均,最大、最小值
Book::sum('price')
=> 300
Book::avg('price')
=> 150.0
Book::max('price')
=> 200
Book::min('price')
=> 100
```
(方法三)軟刪除,程式碼下方有圖示,id=2而不是等於1
```php=
// model
use Illuminate\Database\Eloquent\SoftDeletes;
use Softdeletes;
// migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('books', function (Blueprint $table) {
//
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('books', function (Blueprint $table) {
//
$table->dropSoftDeletes();
});
}
};
```

(補充)查找被刪除的資料
```terminal
Book::withTrashed()->find(1)
```

### 資料表關聯
1. 一對一
```php=
hasOne() <=> belongsTo()
```
2. 一對多
```php=
hasMany() <=> belongsTo()
```
3. 多對多
需額外再建置一張資料表用來表示關聯
```php=
belongsToMany() <=> belongsToMany()
```
### Factory 工廠模式
#### Step1. 創建工廠
```terminal
php artisan make:factory factoryName --model=modelName
```
#### Step2. 設定工廠
```php=
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Book>
*/
class BookFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
//
'title' => $this->faker->name,
'description' => $this->faker->text,
'price' => $this->faker->numberBetween(10, 300),
];
}
}
```
#### Step3. 利用faker製作假資料
```terminal
// 要先進入tinker
Book::factory()->count(3)->make() // 製作三筆假資料
Book::factory()->make(['title'=>'你好']) // 指定做出來的假資料title欄位值都是'你好'
```
#### Step4. 利用faker產生假資料(進資料庫)
```terminal
Book::factory()->count(3)->create()
```
#### 關聯性:一對多
(以商店的角度)
```terminal
# 一間店有很多本書,所以我創建一間商店時請他幫我新增三本書
# 前面用hsaMany(),這邊用has
Store::factory()->has(Book::factory()->count(3))->create()
Store::factory()->hasBooks(3)->create() # 效果同上,但命名要遵循CoC才可以這樣做
```
(以書的角度)
```terminal
# 見一本書,也順便來商店也一起建
# 前面用belongsTo(),這邊用for
Book::factory()->for(Store::factory())->create(['title'=>'為自己學'])
Book::factory()->forStore()->create(['title'=>'為自己學']) # 效果同上,但命名要遵循CoC才可以這樣做
```
### 種子資料 seeder(Database Seeding)
(跑預設種子資料)database\seeders\DatabaseSeeder.php
```terminal
php artisan db:seed
```
(跑指定種子資料)
```terminal
php artisan db:seed --class=seederName
```
(創建種子資料)
```terminal
php artisan make:seeder seederName
```
### 更多migration相關操作參考官方文件:https://laravel.tw/docs/5.2/migrations
## Model(ORM > Active Record > Model)
1. 幫我們與資料庫交互的抽象層
2. 不等於資料庫本身
3. 將資料表物件化,其內容包含欄位,基本操作(新、修、刪、更)、商業邏輯
4. Active Record設計模式的下產物,第三點就是其模式的運作
## ORM的解釋與模式 from ChatGPT
在軟體工程中,ORM(物件關聯對映)是一種編程技術,用於在關聯型資料庫和面向物件導向語言之間建立映射,從而允許使用面向物件的方式來操作資料庫。
根據使用的方法和模式,ORM 可以分為幾種不同的類型或模式。以下是一些常見的 ORM 模式:
1. **Active Record 模式**:
- Active Record 是一種最簡單和最常見的 ORM 模式。在這種模式中,每個資料表對應於一個類(Active Record 類),每個實例(物件)表示資料庫表中的一行資料。
- Active Record 物件負責處理自己的資料持久化和業務邏輯,通常會封裝 CRUD(建立、讀取、更新、刪除)操作。
2. **Data Mapper 模式**:
- Data Mapper 是一種更為分離的 ORM 模式。在這種模式中,資料物件(Domain Object)和資料庫操作之間有一個單獨的映射層(Mapper)。
- Data Mapper 負責將資料物件和資料庫表之間進行映射,但資料物件本身不包含任何持久化的邏輯。
3. **Table Data Gateway 模式**:
- Table Data Gateway 是一種將資料庫表映射到單個類中的模式。在這種模式中,每個表都有一個對應的 Gateway 類,負責提供對該表的資料操作方法。
- 該模式通常會將資料庫表的每一行資料表示為物件,而每個 Gateway 類封裝了對應表的資料訪問邏輯。
4. **Unit of Work 模式**:
- Unit of Work 是一種用於管理事務和資料變更的模式。在 ORM 中,Unit of Work 負責追蹤物件的變更,並在事務提交時將這些變更保存到資料庫中。
這些模式可以單獨使用,也可以結合使用,具體取決於應用程式的需求和開發人員的偏好。不同的 ORM 框架可能會支持不同的模式,或者在其實現中結合多種模式來提供更靈活和強大的功能。
### CoC(Convention over Configuration)慣例大於設定
#### Model 與 Table的範例(左M右T)
Post -> posts
Student -> students
MyBooK -> my_books
#### 可複寫系統慣例,範例如下
情況:M=Post,T=user_posts(正常是要posts)
```php=
# 透過更改指向,改變對應table(user_posts表)
Protected $table = "user_posts";
```
#### 可複寫預設主鍵,範例如下(小心使用)
```php=
# 將主鍵更改為(post_id)
Protected $primaryKey = "post_id";
```
## MVC 架構

**M,Model資料交互 V,View畫面呈現 C,Controller流程控制**
### 簡單解釋:透過路由(Route->web.php)去選擇C,並透過C去與M、DB索要資料回傳給C,最後再由V呈現
## Laravel 預設使用'Blade'樣板引擎
### 詳細參考官方文件: https://laravel.tw/docs/5.3/blade
1. 如果有需要在撰寫的網頁檔使用相關語法,需使用固定格式檔名,格式:'filename.blade.php'
2. 該規則是參考 ASP.NET Razor
3. 盡量使用提供的樣板語法,可避免程式碼混亂情形發生
## Blade範例
1. {{ $variableName }}
```php=
// 後端
$js = '<script>alert("hi");</script>';
// 前端
{{ $js }} // 經過處理,輸出字串
{{!! $js !!}} // 不處理直接執行裡面的程式碼,會有跳窗跑出來
```
2. @if...@endif,其他敘述同理如:for、unless(ifnot的意思)
```php=
@if(true)
123
@endif
```
3. for 與 foreach
```php=
// foreach
@if(count($people) > 0)
@foreach($people as $item)
<li>{{ $item }}</li>
@endforeach
@endif
// for
@if(count($people) > 0)
@for($i = 0; $i < count($people); $i++)
<li>{{ $people[$i] }}</li>
@endfor
@endif
```
4. $loop的使用(first第一筆,last最後一筆,even第偶數筆,odd第奇數筆)
```php=
@if(count($people) > 0)
@foreach($people as $item)
@if($loop -> first || $loop -> last)
<li><strong>{{ $item }}</strong></li>
@elseif($loop -> even)
<li>*{{ $item }}*</li>
@elseif($loop -> odd)
<li>^{{ $item }}^</li>
@else
<li>{{ $item }}</li>
@endif
@endforeach
@endif
```
5. 套用layout
佈局檔
1. @yield('locName') -> 挖空處
```php=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My blog - @yield('title')</title>
</head>
<body>
<main>
@yield('main')
</main>
<footer>
@yield('footer')
</footer>
</body>
</html>
```
目標檔
1. @extends('layouts/layoutname') 選擇哪個佈局檔
2. @section('locName','contents') 填入位置(單行寫法)=>*title*常用
3. @section('locName')...@endsection 多行寫法
```php=
@extends('layouts/application')
@section('title', 'blade practice')
@section('main')
<h1>Hi</h1>
<h2>{{ $name }}</h2>
{{ $js }}
<!--{{!! $js !!}}-->
@if(true)
123
@endif
@if(count($people) > 0)
@foreach($people as $item)
<li>{{ $item }}</li>
@endforeach
@endif
<br>
<br>
@if(count($people) > 0)
@for($i = 0; $i < count($people); $i++)
<li>{{ $people[$i] }}</li>
@endfor
@endif
<br>
<br>
@if(count($people) > 0)
@foreach($people as $item)
@if($loop -> first || $loop -> last)
<li><strong>{{ $item }}</strong></li>
@elseif($loop -> even)
<li>*{{ $item }}*</li>
@elseif($loop -> odd)
<li>^{{ $item }}^</li>
@else
<li>{{ $item }}</li>
@endif
@endforeach
@endif
@endsection
```
## Debug
### 找不到目標畫面
1. 檢查web.php有沒有打錯字
2. 檢查檔案位置(抓取網頁檔順序問題public > views > others )
3. 參數設置問題
4. 檢查Controller裡function回傳的路徑
### 資料庫問題
1. 檢查.env檔案
2. 使用php artisan migrate工具進行同步or退回前一版本