iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
Software Development

一套真實運作中的 Laravel 系統,拆解它的原生機制系列 第 25 篇

Day 25:Media Library 整合——覆寫一個方法,讓檔案路徑依 Model 好排查

  • 分享至 

  • xImage
  •  

前言:「這個檔案存在哪個資料夾?」——一個問題,兩種答案

「這張圖片的檔案在伺服器上到底存在哪裡?」

如果你用過 Spatie 的 Media Library 套件管理檔案上傳,可能已經知道它預設的儲存路徑長什麼樣:一長串隨機產生的 ID 當資料夾名稱,檔案本身埋在裡面。這個設計本身沒有錯——避免路徑衝突、避免可預測性——但當你真的要去伺服器上排查「這個 Model 底下到底有哪些檔案」時,這種路徑結構完全幫不上忙。今天要看的是一個只有十幾行程式碼的類別,怎麼解決這個問題。

今日目標

  • 理解 Media Library 套件預設路徑結構的設計邏輯,以及它犧牲了什麼
  • 看一個真實的 PathGenerator 覆寫範例,只改一個方法解決排查困難
  • 學會「套件預設值不一定適合你的情境,該覆寫哪一層」的判斷方式

本文主體

套件預設路徑:安全,但不好排查

Media Library 套件預設的路徑生成邏輯,是用每筆媒體紀錄自帶的隨機 ID 當作資料夾名稱。這個設計的好處很直接:不同筆紀錄的路徑天生不會撞在一起,也沒辦法從路徑猜出裡面存的是什麼內容。

但反過來看,這也是它的缺點:如果你要在伺服器的檔案系統裡人工排查「某個特定新聞底下的附件檔案在哪」,光看路徑完全看不出線索——一堆隨機 ID 資料夾,沒有任何一個能一眼看出它屬於哪個 Model、哪一筆紀錄。

真實案例:覆寫 getBasePath(),換成人類看得懂的路徑

這個系列的素材專案裡,有一個只有十幾行的類別,繼承了套件的預設路徑產生器,只覆寫了其中一個方法——getBasePath()。改寫後的邏輯是:拿到媒體所屬的 Model 類別名稱(轉成小寫),組合 Model 所屬紀錄的 ID、以及這筆媒體紀錄自己的 ID,串成一個新的路徑結構——資料夾長得像「模型名稱 / 該筆資料的 ID / 這筆媒體紀錄的 ID」。

用一組對照來看差異:

❌ 套件預設路徑(一串隨機 ID)
storage/media/a1b2c3d4-.../photo.jpg
→ 從路徑完全看不出這個檔案屬於哪個 Model、哪一筆資料,
  要排查只能去資料庫反查

✅ 覆寫 getBasePath(),路徑帶有可讀語意
storage/media/news/42/108/photo.jpg
→ 一眼看出:這是 News 模型、第 42 筆新聞、
  第 108 筆媒體紀錄底下的檔案,
  伺服器上直接用檔案總管排查也看得懂

為什麼只需要覆寫這一個方法

Media Library 套件的路徑生成邏輯被拆成了幾個獨立方法(基礎路徑、轉換後圖片的路徑、響應式圖片的路徑),但這幾個方法內部都是呼叫同一個核心方法來組出基礎路徑,再各自往下延伸。這代表只要覆寫這一個核心方法,其他所有依賴它的路徑(縮圖轉換版本、響應式圖片版本)都會自動套用同一套新的路徑規則,不需要每個方法都重寫一次。

這是一個值得記住的套件擴充模式:遇到套件的某個行為想改,不需要整個重寫套件的核心邏輯,先看它有沒有把「你想改的那一小段」拆成一個獨立、可以被覆寫的方法。多數設計良好的套件都會這樣拆分,找到那個最小的覆寫點,比自己從頭實作一套替代方案划算得多。

這個改動天然銜接一個問題:舊資料怎麼辦

看到這裡,可能會想到一個問題:如果系統已經上線一段時間、累積了不少用舊路徑規則儲存的檔案,換了新的路徑生成器之後,這些舊檔案怎麼辦——新的程式碼會用新規則去讀取路徑,但檔案實際上還躺在舊路徑底下。

這正是明天要講的主題:一支專門處理這種「換了路徑規則,要把歷史資料安全搬過去」的資料遷移 command,怎麼設計才不會在搬遷過程中弄丟或搬壞任何一筆檔案。

今日思考題

回想你專案裡用到的第三方套件,有沒有哪個套件的預設行為讓你在維運時吃過排查上的苦頭?那個行為,套件本身有沒有提供類似「覆寫某個方法」這樣的擴充點,還是真的只能整套重寫?

今日重點回顧

  • Media Library 套件預設的隨機路徑結構安全但難以人工排查
  • 真實案例:覆寫 getBasePath() 這一個方法,換成「模型名稱/資料 ID/媒體 ID」的可讀路徑結構
  • 因為套件把路徑生成邏輯拆成獨立方法、且互相依賴同一個核心方法,只需要覆寫一處,其他相關路徑都會自動套用新規則
  • 遇到套件行為想改,先找有沒有現成的覆寫點,比整套重寫划算

明日預告

明天要看另一個真實的演進案例——一個原本寫死在設定檔或程式碼裡的第三方追蹤碼,後來為什麼、又是怎麼變成後台可以直接設定的欄位。


上一篇
Day 24:Middleware 實戰——CSP header 跟業務導流邏輯,兩種輕量 middleware 長什麼樣
下一篇
Day 26:套件化設定——第三方追蹤碼從寫死到後台可設定的真實演進
系列文
一套真實運作中的 Laravel 系統,拆解它的原生機制 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言