還記得昨天我們用 Plugin,請 Claude 幫我們快速做出一個「進入產品頁 → 產品名稱後面自動加上(全館優惠)」的小功能嗎?
那次我們用到的,是 Magento 最常用、也最安全的一種擴充方式:Plugin 攔截器。
不過在 Magento 裡,還有另一種威力更強大的做法:Preference。顧名思義,Preference 就是「優先權」——當系統要用某個 class 的時候,我們可以偷偷指定:「欸,別用原本的,用我的!」
今天,我們就來用 Preference 實戰一次,繼續體驗 AI 協作開發的威力。
.
.
Preference = 完整替換某個類別的實作
Magento 本身有很多核心 class,例如 Magento\Catalog\Model\Product
。
.
.
如果我們寫一個 Preference,指向我們自訂的 class,那麼以後系統只要用到 Product
,都會自動換成我們的版本。
.
.
這聽起來是不是很暴力?因為它真的是一刀切——你說換掉,它就真的整個換掉。
所以 Preference 的特色是:
.
.
你只需要在 di.xml
裡下這一段:
<preference for="Magento\Catalog\Model\Product"
type="Mrl\PromoTag\Model\Product" />
意思就是:
當系統想要用 Magento\Catalog\Model\Product 時,請改用 Mrl\PromoTag\Model\Product(你開發實用的class) 這個 class。
.
.
.
Preference 最適合用在 你需要全面掌控某個 class 的邏輯,或者 你想修改的是 Plugin 無法攔截的地方,例如 private 方法、protected 方法、建構子(
__construct
)等等。
這些情境下,Plugin 是無能為力的,只有 Preference 能幫你達成目的。
.
.
不過要特別注意的是:Preference 的影響範圍非常大,因為它會直接替換掉原本的 class,導致其他人針對這個 class 所寫的 Plugin 通通不會被執行。這不只可能踩雷,也可能讓你的擴充無意間破壞系統其他邏輯。
.
.
一句話總結:當你需要改的是 Plugin 無法觸及的地方,或你真的需要完全接管某個類別的邏輯時,就該出動 Preference。
.
.
.
說了這麼多不如直接來做,現在就讓我們實戰了解 Preference!
這次一樣請出我的好夥伴 —— Claude Code CLI。
我們只要把需求整理好,丟給它,它就會幫我們產生整包模組。Let's go!
今天我們要做的需求一樣簡單:
幫我們做一個 Magento 2 小模組,進入產品頁時,把產品名稱自動加上「(全館優惠)」。
不過這次我們不走 Plugin,而是:
直接用 Preference,把 Product 類別換掉,覆寫它的 getName()
。
.
.
請幫我建立一個 Magento 2 模組,
需求:當使用者進入產品頁(PDP)時,
在產品名稱後面加上「(全館優惠)」。
功能需求:
- 請使用 Preference 方式
- 不要改資料庫,純顯示層
- 請幫我產生以下檔案:
- registration.php
- etc/module.xml
- etc/frontend/di.xml
- Model/Product.php (繼承原本的 Product 並改寫 getName())
.
.
生成完成!
.
.
這裡可以看到:
registration.php
:讓 Magento 知道這是個新模組etc/module.xml
:定義模組名稱和版本etc/frontend/di.xml
:設定 Preference 的接管Model/Product.php
:我們實作 getName()
的地方,也就是整個功能的核心di.xml
怎麼註冊 Preference這次我們用的是 Preference,所以 di.xml
裡的設定會長這樣:
這段的意思是:
當 Magento 嘗試載入 Magento\Catalog\Model\Product 這個 class 時,請改用我們自己寫的 Mrl\PromoNameSuffix\Model\Product!
跟 Plugin 不一樣的是,這裡我們沒有攔截某個特定的方法,而是整個 class 都被我們接管了。
之後系統裡所有用到 Product
的地方,都會自動轉向我們的版本。
.
.
Product.php
接下來看到我們指定接管class的地方:
這裡我們做了什麼?
Product
類別getName()
方法小提醒:因為我們是繼承原本的 Product,所以其他功能(像是價格、描述、庫存等方法)都不用自己再重寫,會自動沿用原本的邏輯。
只要改寫你需要客製的那幾個方法就好!
這樣一來,系統裡只要呼叫 getName()
的地方,都會自動使用我們這個版本,名稱也就會自動加上我們指定的後綴文字啦!
.
.
寫完後記得輸入:
php bin/magento module:enable Mrl_PromoTag
php bin/magento setup:upgrade
php bin/magento cache:flush
.
.
一樣打開產品頁,名稱後面已經自動加上了「(全館優惠)」!
這次不靠 Plugin,而是靠 Preference 的強制覆寫,效果一樣直接生效。
.
.
.
走到這裡,我們已經實作過 Magento 最常見的三種擴充方式:
.
.
一路實作下來,我開始慢慢抓到它們之間的差異,也更清楚什麼時候該出哪一招。
每一種擴充方式就像三種武功——各有特性,各有代價,用得好就能事半功倍。
.
.
到現在為止,我們已經漸漸掌握住 Magento 後端開發的精髓了。
請繼續跟上我們的旅程,接下來——我們即將進入更完整的實戰!