---
# System prepended metadata

title: Never 週活動紀錄-2-from20240403
tags: [活動紀錄]

---

# Never 週活動紀錄-from20240403
###### tags: `活動紀錄`
<!--  設定字體陰影-->
  <style>
    /* 多重陰影 */
    h1 {
      text-shadow: 0 0 3px #FF0000, 0 0 5px #0000FF;
    }

    h2 {
      color: white;
      text-shadow: 1px 1px 2px black, 0 0 25px blue, 0 0 5px darkblue;
    }

    /* 環繞邊框 */
    h3 {
      color: coral;
      text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
    }
  </style>
<!--  設定字體陰影-->
## ==20240404==
[準備資安考試-內容網址](https://hackmd.io/rcL-zuQCTiaDTJRBF4W3bQ)
    
- ## 分散式阻斷服務攻擊...等...
            
## ==20240403==

- ## Laravel 外鍵約束
    - 使用 Laravel 進行外键约束的示例

    假設我們有兩個模型：User和Post，並且Post模型有一個user_id欄位，該欄位是對User模型的外鍵。
    
     User
    ```js=
    class User extends Model
    {
        protected $fillable = ['name'];

        public function posts()
        {
            return $this->hasMany(Post::class);
        }
    }
    ```
    Post
    ```js=
    class Post extends Model
    {
        protected $fillable = ['title', 'content', 'user_id'];

        public function user()
        {
            return $this->belongsTo(User::class);
        }
    }

    ```
    
    在Migration檔案中，我們可以新增外鍵約束
    
    ```js=
    class CreatePostsTable extends Migration
    {
        public function up()
        {
            Schema::create('posts', function (Blueprint $table) {
                $table->id();
                $table->string('title');
                $table->text('content');
                $table->unsignedBigInteger('user_id');
                // 新寫法
                $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
                // 傳統方式寫法
                // $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
                $table->timestamps();
            });
        }
        ...
    }
    ```

   關於在Laravel Migration 檔案中建立外鍵約束 有二種寫法
    二個有何不同？
    - ### 傳統的方式
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        - 使用foreign()方法建立外鍵約束，
        - 然後透過references()方法指定參考表和參考列(例如所有的id欄位，稱為列(row),因為id是欄位column)，
        - 最後使用onDelete('cascade')指定外鍵的刪除行為。
        
    - ### Laravel 7 及更高版本的新方式
        $table->foreignId('user_id')->constrained('users')->onDelete('cascade');
        - 使用foreignId()方法直接建立外鍵欄位，
        - 使用constrained()方法將外鍵約束與特定的表和列進行關聯，
        - 最後使用onDelete('cascade')指定外鍵的刪除行為。
   
    兩種寫法<font color=red>實現的功能相同</font>，都會在資料庫中建立一個外鍵約束，並且指定了當參考表中的對應記錄被刪除時，與之關聯的記錄也會被級聯刪除。<font color=red>區別在於語法和寫法的簡潔性</font>，新的foreignId()和constrained()方法提供了更簡潔的方式來創建外鍵約束，使程式碼更易讀和易於維護。
    
    - 比較表
    
        | 傳統方式                        | 新方式                        |
        |-------------------------------|-------------------------------|
        | $table->foreign('user_id')    | $table->foreignId('user_id')  |
        |        ->references('id')     |       ->constrained('users')  |
        |        ->on('users')          |                               |
        |        ->onDelete('cascade'); |       ->onDelete('cascade');  |

    - 各個外鍵約束刪除onDelete(類型)操作類型:
        1. **Cascade（級聯）**：當參考表中的相應記錄被刪除時，與該記錄有外鍵關係的當前表中的相應記錄也將被自動刪除。這可以確保數據的一致性，但要小心使用，以免誤刪數據。
        2. **Restrict（限制）**：當參考表中的記錄被刪除時，如果在當前表中有相應的外鍵引用，則不允許刪除參考表中的記錄。這樣可以防止意外刪除數據，但需要手動處理相關的外鍵引用問題。
        3. **Set Null（設置為空）**：當參考表中的記錄被刪除時，與該記錄有外鍵關係的當前表中的相應外鍵列將被設置為 NULL。這樣做可以避免刪除記錄時的完整性違規，但需要確保相應的欄位允許 NULL 值。
        4. **No Action（不採取任何操作）**：當參考表中的記錄被刪除時，不對當前表中的相應外鍵列進行任何操作。這意味著如果存在外鍵關係，則刪除操作將被阻止，直到手動處理相關的外鍵問題。
        5. **Set Default（設置默認值）**：當參考表中的記錄被刪除時，與該記錄有外鍵關係的當前表中的相應外鍵列將被設置為其默認值。這樣做可以確保數據的一致性，但需要確保外鍵列有合適的默認值。

        這些外鍵約束操作類型提供了不同的行為選擇，可以根據實際應用場景來選擇最合適的操作類型。

- ## @input="$emit('update:modelValue', event.target.value)"

    ```js=
    // 定義 props
    defineProps({
      modelValue: {
        type: [String, Number],
        required: true,
      },
    });

    // 定義 emits
    defineEmits(['update:modelValue']);
    ...
    ;
    </script>

    <template>
      <input
        :value="modelValue"
        @input="$emit('update:modelValue', $event.target.value)"
        ref="input"
      />
    </template>
    ```
    - **DefineEmits()** <font color=red>會返回一個名為 emit 的函數</font>，用於觸發自定義事件。這個 emit 函數接受一個事件名和一個可選的參數列表，然後將事件派發給當前組件的事件監聽器。

        若是 
        ```js=
        const x = defineEmits(['update:modelValue']);
        console.log(x)
        ```

        會看到 <font color=red>(event, ...args) => instance.emit(event, ...args)</font>
        這便是 **emit函數**

        如果無法取得 emit 還有一個方式
        ```js=
        const instance = getCurrentInstance(); // 獲取组件實例(instance)
        const emit = (event, ...args) => instance?.emit(event, ...args); // 從组件實例中獲取 emit 函数
        ```
        instance 當前组件實例 的內容
        ![image](https://hackmd.io/_uploads/HJ_9sAGyC.png)
        黃色框框內便是 emit 函數 
        
    - 在Vue模板(template)中，$emit是用來觸發自訂事件的方法，而emit是在Vue3 中setup函數中的一個函數參數，用於觸發自訂事件。通常情況下，只需要<font color=red>在模板中使用$emit來觸發自訂事件</font>。

    - 對於事件對象，Vue模板(template)中的$event是一個特殊的變量，用於表示目前觸發的事件對象。因此， 模板(template)中，可以使用$event來存取事件物件的屬性和方法，例如$event.target.value用於取得輸入框的值。
    
    - <font color=red>在 Vue.js 的模板中，$event 只能在事件處理器內部使用</font>。換句話說，當處理一個事件時（比如 @click、@input 等），可以使用 $event 來訪問觸發該事件時相關的數據。

     - 在Vue的setup函數中，事件物件通常透過函數參數傳遞，因此你可以給參數取任意的名字，通常使用event或其他你喜歡的名稱。所以，在setup函數中，你可以使用event或其他的名字來存取事件物件。
    
    - 在Vue 的setup函數中 這句話 釋疑
    如果是使用了 <script setup>，就不再需要明確地聲明 setup 函數，因為 <script setup> <font color=red>會隱式地創建 setup 函數並將它的返回值作為組件的配置對象</font>。在 <script setup> 中，事件處理器會直接接收到事件物件，而不需要額外地在 setup 函數中聲明。
    
    - 所以將 "$emit('update:modelValue', $event.target.value)" 寫成函式的方法
     
        TextInputTry 元件
        ```js=
        <script setup>
        ....

        defineProps({
          modelValue: {
            ...
        });

        const emit = defineEmits(['update:modelValue']);
        ...

        // 定義 handleInput 函式，用於處理輸入事件
        const handleInput = (event) => {
          const newValue = event.target.value;
          // 通過 emit 函式觸發 update:modelValue 事件，並將新值作為參數傳遞給該事件
          emit('update:modelValue', newValue);
        };
        </script>

        <template>
          <input
            :value="modelValue"
            @input="handleInput"
            ref="input"
          />
        </template>
        ```
        
        使用 TextInputTry 元件
        ```js=
        ...
        const x = ref('');
        ...
        <div>
          <text-input-try :model-value="x" @update:model-value="updateData" />
          <p>Parent value: {{ x }}</p>
        </div>
        ```
        會發現還是<font color=red>@input="$emit('update:modelValue', $event.target.value)"</font>的寫法簡潔。
   
- ## watch 與 addEventListener： 
    watch 和 addEventListener 都是用於監聽事件的機制，但它們在使用情境和功能上有所不同：
    實際上來說應該說
    <font color=red>watch(是監看數據)->數據是看得見的。
    listener(是監聽事件)->事件是觸發，觸發是行為，是動作。
    很明顯 聽 與 看 就是不同的事情，所以不需要一起比較，應該分開來各自討論。
    </font>
  
    | 特點        | watch                 | 
    |------------|-----------------------|
    | 用於        | <font color=red>監聽 Vue 實例中的數據變化</font>|
    | 語法        | Vue.js 中的 API       |
    | 使用方式     | 在 Vue 組件的函數中使用 |
    | 監聽對象     | Vue 實例中的數據變化、computed 屬性|
    | 回調函數參數  | 新值、舊值            |
    | 觸發時機     | 監聽的數據發生變化時    |
    | 主要用於     | Vue 組件中的數據監聽   |
    | 處理的事件類型| Vue 實例中的數據變化事件| 
    
    | 特點        | addEventListener                 |
    |------------|-----------------------------------|
    | 用於        | <font color=red>監聽 DOM 元素上的事件</font>|
    | 語法        | JavaScript 原生方法 |
    | 使用方式     | 在 JavaScript 中使用 |
    | 監聽對象     | DOM 元素上的事件（如 click、 input等）|
    | 回調函數參數  |  事件對象（event object） |
    | 觸發時機     | 監聽的事件發生時 |
    | 主要用於     | DOM 事件監聽  |
    | 處理的事件類型| DOM 元素上的各種事件（如 click、input、mouseover 等） |
    
- ## Instance(實例、實體)
    在程式設計中，"實例"（instance）通常指的是根據類別(class)建立的物件。在物件導向程式設計中，類別是一種抽象的概念，描述了具有相同屬性和方法的一組物件的特徵。透過類別可以建立多個物件(object)，這些物件被稱為類別的實例。

    在Vue.js 中，"實例"（instance）通常指的是Vue 元件的實例。當你建立一個Vue 元件時，你實際上建立了一個Vue 實例，該實例繼承了Vue.js 框架提供的一系列功能，包括資料響應式、生命週期鉤子函數、計算屬性、方法等。這個實例將包含元件的所有邏輯和狀態，並且可以在你的應用程式中被實例化和重複使用。

    例如，在Vue 元件中，你可以透過new Vue()或Vue.js 提供的其他方法來建立一個Vue 實例，然後在該實例中定義元件的各種屬性和方法。這個實例會被掛載到你的應用程式中，並負責管理該元件的所有行為和狀態。

    總而言之，在程式設計中，"實例"通常指的是根據類別或建構子建立的物件(object)，而在Vue.js 中，"實例"通常指的是Vue 元件的實例，它包含了元件的所有邏輯和狀態。
    
- ## Middleware 權限控制
    假設有一組路由需要經由
    ```js=
    Route::prefix('order-service')->middleware(['auth', 'verified', 'role.weight:1|2|3'])->controller(OrderServiceController::class)->group(function () { 
    ...
    });
    ```
    此路由需要透由一個名為 'role.weight' 的 middleware，並傳遞 '1|2|3'(權限為1或2或3)的參數，此處的'role.weight'其實是一個別名，我們建立一個的是一個名為RroleWeight的middleware。
    
    - 1. ### 自建middleware
        首先需要先另外建立middleware
        
        **$ php artisan make:middleware RoleWeight**
        
        將在 app/Http/Middleware 目錄下建立一個名為 RoleWeight 的中介軟體類別。
        
    - 2. ### 註冊中介軟體 $middleware 及 中介軟體群組 $middlewareGroups
        - 請確保在 $middleware 中僅註冊<font color=red>不需要參數的<font size=4>**全域**</font>中介軟體</font>，而將<font color=red>需要參數的中介軟體註冊到 middlewareGroups 中</font>。
        
        - 註冊中介軟體$middleware：
              
            在 Laravel 中，$middleware 屬性是用於註冊全域</font>中介軟體的，這些中介軟體將應用於每個 HTTP 請求，<font color=red>而不是在特定路由群組中</font>。如果您在 $middleware 中註冊了中介軟體，並且這些中介軟體<font color=red>需要額外的參數（如您的 RoleWeight 中介軟體），**將會導致錯誤**</font>，因為全域中介軟體不接受參數。  
            
            在 **app/Http/Kernel.php** 檔案的 $middleware 陣列中註冊中介軟體。
            ```js=
            protected $middleware = [
                // 其他中介軟體...
                'role' => \App\Http\Middleware\RoleWeight::class,
            ];
            ```
            
        - 中介軟體群組 $middlewareGroups
        
            如果您想要在路由群組中使用中介軟體<font color=red>並且該中介軟體需要參數</font>，則應該將它註冊到 middlewareGroups 中，而不是 $middleware。
            
            在 **app/Http/Kernel.php** 檔案的 $middlewareGroups 陣列中註冊中介軟體。
            ```js=
            protected $middlewareGroups = [
                'web' => [
                    \App\Http\Middleware\EncryptCookies::class,
                    ...
                ],

                'api' => [
                    'throttle:api',
                    ...
                ],
                    // 自定義中介軟體組
                'custom' => [
                    \App\Http\Middleware\RoleWeight::class,
                    // 其他自定義中介軟體...
                ],
            ]
            ```
     - 3. ### 註冊中介軟體別名 $middlewareAliases

        $middlewareAliases 屬性用於註冊中介軟體別名，因此可以認為在這裡添加別名也是一種註冊行為。這些別名允許在路由定義中使用更簡潔的方式來引用中介軟體。

        當在 $middlewareAliases 中註冊了中介軟體的別名後，可以在路由定義中使用這些別名，而不必每次都寫完整的中介軟體類名。這樣可以使代碼更加簡潔、易讀且易於維護。
        
        ```js=
        protected $routeMiddleware = [
            'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
            'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
            ...
            // 權限中介軟體別名...
            'role.weight' => \App\Http\Middleware\RoleWeight::class,
        ];
        ```
        
        注意到 是用小寫並且用 '.' 隔開兩個單字 如果想命名 'RoleWeight' 則以 'role.weight' 當別名，可以參看上方原本就有的 'auth.basic' 並不一定要與原來命名 'AuthenticateWithBasicAuth' 都相同。
    
     - 4. ### $middleware 傳參數
        此路由透由一個別名為 'role.weight' 的 middleware 傳遞 '1|2|3'(權限為1或2或3)的參數。
        
        **...->middleware(['role.weight<font color=red>:1|2|3'</font>])->...**
        
     - 5. ### middleware 接收權限參數及處理權限
        要讓中介軟體接收參數，您可以在定義中介軟體時，在 handle 方法中添加額外的參數。然後，在路由定義中將這些參數傳遞給中介軟體。

        範例：
        
        - 剛建立middleware時
            ```js=
            class RoleWeight
            {
                public function handle($request, Closure $next)
                {
                    return $next($request);
                }
            }
            ```
        
        - <font color=red>**自己添加參數 $Roles**</font>
        
            ```js=
            class RoleWeight
            {
                public function handle($request, Closure $next, $roles)
                {
                    // 在這裡檢查使用者的角色是否符合要求
                    // 您可以使用 $role 變數來檢查特定角色
                    // 如果使用者不符合要求，您可以返回相應的響應或重定向

                    return $next($request);
                }
            }
            ```
        
        - <font color=red>**自己視需求添加處理過程**</font>
            - <font color=red>**需要切割**輸入參數為一陣列</font>

                ```js=
                class RoleWeight
                {
                    public function handle($request, Closure $next, $roles)
                    {
                        $userRole = request->user()?->role(); // 假設您有一個方法可以取得使用者的角色
                        $allowedRoles = explode('|', $roles); //切割所有允許角色成陣列

                        if (in_array($userRole, $allowedRole)) {
                            return $next($request);
                        }

                        return redirect()->route('login'); // 或者根據您的應用程式需求返回其他響應
                    }
                }
                ```
            
           - <font color=red>**不需要切割**輸入參數為一陣列</font>
                此處需要將傳入的字串參數切割成一陣列，所以不方便，還可以進一步，修改成不需要切割的方式。
                
                修改使用 PHP 5.6 以後引入的<font color=red>可變長度引數 (...$roles)</font>。這允許您在路由中直接指定多個角色，而無需在中介軟體中進行字串分割。
                
                當您使用可變長度引數時，請確保在函數調用時<font color=red>使用逗號將每個參數分隔開</font>，以便 PHP 正確地將它們解析<font color=red>並收集到陣列中</font>。
                ```js=
                class RoleWeight
                {
                    public function handle($request, Closure $next, ...$roles)
                    {
                        $userRole = $request->user()?->role(); // 假設您有一個方法可以取得使用者的角色

                        if (in_array($userRole, $roles)) {
                            return $next($request);
                        }

                        return redirect()->route('login'); // 或者根據您的應用程式需求返回其他響應
                    }
                } 

                ```
                
                參數可直接傳入1,2,3；其中參數以，隔開
                ```laravel=
                Route::group(['prefix' => 'admin','middleware' => ['role.weight:1,2,3']], function() { 
                ...
                });
                ```
                
    - ## PHP 可變長度引數（variable-length argument）的語法
        可以在函數或方法的參數列表中使用 ... 來接受可變數量的參數，這些參數將被收集到一個陣列中。
        
        使用可變長度引數 (...$args) 的情況，需要在函數調用時使用逗號將參數分隔開。這樣 PHP 才能將這些參數正確地收集到陣列中
        
        - 範例
            Laravel 中 
            ```laravel=
            function myFunction(...$args) {
                var_dump($args);
            }
            ```
            
            呼叫並傳遞任意數量的參數：
            
               myFunction('apple', 'banana', 'orange');
                
    - ## $validator        
        在Laravel 的表單驗證過程中，$validator物件在驗證失敗時<font color=red>會停止請求繼續執行</font>，而在驗證成功時不會對請求產生影響，也不會修改請求資料。
        
        因此，即使沒有使用$validated，您仍然可以直接使用 $request->all() 或 $request->input() 來獲取請求資料
        
        或者使用 $validator->validated() 也可以。
        
        一般 $validator 範例
        
        ```laravel=
        use Illuminate\Http\Request;
        use Illuminate\Support\Facades\Validator;

        class UserController extends Controller
        {
            public function store(Request $request)
            {
                // 定義驗證規則
                $validator = Validator::make($request->all(), [
                    'name' => ['required', 'string', 'max:255'],
                    'email' => ['required', 'email', 'max:255', 'unique:users'],
                    'password' => ['required', 'string', 'min:8', 'confirmed'],
                ]);

                // 執行驗證
                if ($validator->fails()) {
                    return redirect()->back()
                                ->withErrors($validator)
                                ->withInput();
                }

                // 如果驗證通過，直接在這裡使用 $request->all() 或 $request->input()
                // 或者使用 $validator->validated() 也可以
                
                // 獲取通過驗證的 'name' 欄位的值
                // $name = $validated['name'];
                // 獲取通過驗證的 'email' 欄位的值
                // $email = $validated['email'];
                // 獲取通過驗證的 'password' 欄位的值
                // $password = $validated['password'];
                
                $data = $request->all();
				 
                // 在這裡使用請求數據進行其他操作，例如創建用戶

                return redirect('/')->with('success', '用戶創建成功！');
            }
        }
        ```
        
        - ### 使用Laravel 完整的 $validator 驗證器來驗證請求資料
        
            validator = Validator::make($input, $rules, $messages, $naem);
                
          Validator::make()：這是Laravel 提供的用於建立驗證器實例的靜態方法。
          
          它接受四個參數：
            - 請求資料($input): 是要驗證的數 。
            - 驗證規則($rules): 是驗證規則。
            - 自訂錯誤訊息($messages): 是自訂錯誤訊息，用於覆蓋預設的驗證錯誤訊息。
            - 屬性名稱($attributes): 是屬性名稱。

            範例
            
            ```laravel=
             $validator = Validator::make(
                //第一個參數 請求資料
                $request->all(),
                [
                    'name' => ['required', 'string', 'max:255'],
                    'user_address' => ['string', 'max:255'],
                    'user_phone' => ['string', 'max:255'],
                    'user_bank' => ['string', 'max:255'],
                ],
                [
                    'required' => ':attribute 不能留空',
                    'max' => ':attribute 不能超過255個字',
                ],
                [
                    'name' => '名稱',
                    'user_address' => '通訊地址',
                    'user_phone' => '電話',
                    'user_bank' => '轉帳資料',
                ]
            );
            ```

            - 第一個參數 請求資料 $input: 是要驗證的數
                若使用 $request->all()：這個方法傳回請求中的所有數據，以關聯數組的形式。

            - 第二個參數是驗證規則，它指定了要對請求資料進行的驗證。
                在這個例子中，'name'、'user_address'、'user_phone' 和'user_bank' 欄位都分別具有一組驗證規則。

            - 第三個參數是自訂錯誤訊息。在這個陣列中，可以為每個驗證規則指定自訂的錯誤訊息。例如，'required' 規則的自訂錯誤訊息是':attribute 不能留空'，其中':attribute' 是一個佔位符，會被實際的欄位名稱取代。

            - 第四個參數是屬性名稱數組，它用於指定每個欄位的自訂名稱。這樣做的目的是為了在錯誤訊息中使用更友善的欄位名稱。

