---
# System prepended metadata

title: Laravel 筆記

---

# 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. 單欄寫入
![image](https://hackmd.io/_uploads/Hk3STC8TT.png)
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'
    ];
}

```
![image](https://hackmd.io/_uploads/rk_oTxDaT.png)
### tinker操作（R,read）
1. 簡單查詢
![image](https://hackmd.io/_uploads/rJQVNbwpT.png)
2. 進階查詢
尋找特定字串
![image](https://hackmd.io/_uploads/rklDSZwT6.png)
指定排序方式
![image](https://hackmd.io/_uploads/By2QUbDTT.png)

### tinker操作（Ｕ,update & D,delete）
1. 更新
（方法一）改值
![image](https://hackmd.io/_uploads/HywvxoKaT.png)
（方法二）重新填值
![image](https://hackmd.io/_uploads/HkrCejFap.png)
（方法三）單次大量修改欄位值
![image](https://hackmd.io/_uploads/SJunZoYT6.png)

2. 刪除
（方法一）利用id找到該筆資料並全部刪除
![image](https://hackmd.io/_uploads/By_i4oFpa.png)
（方法二）同上
![image](https://hackmd.io/_uploads/rJM_BoYp6.png)





### 操作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();
        });
    }
};

```
![image](https://hackmd.io/_uploads/Sk3AG05pa.png)

（補充）查找被刪除的資料
```terminal
Book::withTrashed()->find(1)
```
![image](https://hackmd.io/_uploads/H1iDQ0qTT.png)

### 資料表關聯
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 架構

![image](https://hackmd.io/_uploads/HJtvacbaT.png)
**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退回前一版本