Laravel की $casts प्रॉपर्टी उन सुविधाओं में से एक है जो बिना ज़्यादा ध्यान आकर्षित किए आपके डेटा हैंडलिंग के तरीके को आकार देती हैं। ऐरे (array) में boolean या datetime जैसा बिल्ट-इन टाइप डालें, और Eloquent स्वचालित रूप से कच्चे डेटाबेस स्ट्रिंग्स को आपके कंट्रोलर्स या व्यूज़ तक पहुँचने से पहले कुछ अधिक उपयोगी चीज़ में बदल देता है। यह आपके कोड को व्यवस्थित रखता है। लेकिन जैसे ही आप उस ऐरे के अंदर सीधे अपने स्वयं के हेल्पर को कॉल करने की कोशिश करते हैं, फ्रेमवर्क विरोध करता है। 'username' => 'encrypt_data()' जैसा कुछ लिखना काम नहीं करेगा। Laravel या तो एक नेटिव कास्ट कीवर्ड की अपेक्षा करता है या फिर एक ऐसी क्लास की जो CastsAttributes इंटरफ़ेस को लागू (implement) करती हो। यह आवश्यकता इसलिए है क्योंकि कास्टिंग लेयर Eloquent के हाइड्रेशन (hydration) और सीरियलाइजेशन (serialization) चक्र के बहुत गहराई में चलती है; इसे रनटाइम पर मौजूद न होने वाले किसी मनमाने फंक्शन स्ट्रिंग के बजाय एक स्पष्ट अनुबंध (contract) वाले अनुमानित ऑब्जेक्ट की आवश्यकता होती है।
$casts ऐरे में हेल्पर फंक्शन क्यों विफल होते हैं
जब Eloquent एक मॉडल लोड करता है, तो यह प्रत्येक कॉलम को बदलने का निर्णय लेने के लिए $casts ऐरे को स्कैन करता है। फ्रेमवर्क विशिष्ट प्रिमिटिव्स—string, integer, array, encrypted, इत्यादि—को पहचानता है, और यह उन पूरी तरह से क्वालिफाइड क्लास नामों को भी पहचानता है जो CastsAttributes को लागू करते हैं। यह स्ट्रिंग को कोड के रूप में इवैल्यूएट (evaluate) नहीं करता है। इसलिए 'encrypt_data()' को एक अज्ञात कास्ट टाइप माना जाता है, जिससे एरर (error) आता है। भले ही Laravel इसे पार्स (parse) कर लेता, लेकिन आपके फंक्शन में मॉडल इंस्टेंस, एट्रिब्यूट की (key), वर्तमान वैल्यू और आस-पास के एट्रिब्यूट्स को सही क्रम में पास करने का कोई विश्वसनीय तरीका नहीं होता। यह इंटरफ़ेस विशेष रूप से आपके कस्टम लॉजिक और Eloquent के इंटरनल के बीच उस तालमेल (handshake) को मानकीकृत करने के लिए मौजूद है।
इस अंतर को पाटने के आपके पास दो ठोस तरीके हैं। एक लंबे समय तक पुन: उपयोग (reuse) के लिए बेहतर है। दूसरा तब तेज़ है जब आपको केवल एक ही मॉडल के अंदर त्वरित पैच की आवश्यकता हो।
विधि 1: एक कस्टम कास्ट क्लास लिखें
यदि वही ट्रांसफॉर्मेशन कई फ़ील्ड्स पर लागू होता है या कई मॉडल्स में फैला हुआ है, तो एक समर्पित कास्ट क्लास एक बेहतर विकल्प है। यह अपनी अलग फ़ाइल में रहता है, इसे अलग से यूनिट-टेस्ट किया जा सकता है, और यह आपके मॉडल्स को बार-बार होने वाले बॉयलरप्लेट (boilerplate) से मुक्त रखता है।
app/Casts/CustomEncrypt.php बनाकर शुरुआत करें। नेमस्पेस (namespace) आपके ऑटोलोडिंग सेटअप से मेल खाना चाहिए, जो आमतौर पर App\Casts होता है। क्लास को Illuminate\Contracts\Database\Eloquent\CastsAttributes को लागू करना चाहिए, जो आपको दो मेथड: get और set परिभाषित करने के लिए बाध्य करता है।
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class CustomEncrypt implements CastsAttributes
{
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
{
return decrypt_data($value);
}
public function set(Model $model, string $key, mixed $value, array $attributes): mixed
{
return encrypt_data($value);
}
}
सिग्नेचर (signatures) मायने रखते हैं। Eloquent प्रत्येक मेथड में चार आर्गुमेंट्स पास करता है। $model वह इंस्टेंस है जिसे भरा या सेव किया जा रहा है, जो आपको अन्य फ़ील्ड्स का निरीक्षण करने की अनुमति देता है यदि आपका लॉजिक उन पर निर्भर है। $key वह कॉलम का नाम है जिसे वर्तमान में कास्ट किया जा रहा है। $value get पर डेटाबेस से आने वाली कच्ची स्ट्रिंग या null है, या set पर उपयोगकर्ता द्वारा दी गई वैल्यू है। $attributes उस रो (row) के लिए कॉलम का पूरा कच्चा ऐरे है। आपको हर बार चारों का उपयोग करने की आवश्यकता नहीं है, लेकिन इंटरफ़ेस के लिए वे आवश्यक हैं।
ऊपर दिए गए get मेथड में, decrypt_data($value) तब चलता है जब Eloquent डेटाबेस से रो को फ़ेच (fetch) कर लेता है और वैल्यू आपके मॉडल तक पहुँचने से पहले। set मेथड में, encrypt_data($value) INSERT या UPDATE से पहले चलता है, जिससे यह सुनिश्चित होता है कि डेटाबेस कभी भी प्लेनटेक्स्ट (plaintext) न देखे।
इसे जोड़ने के लिए, अपने मॉडल के $casts ऐरे के अंदर क्लास का संदर्भ (reference) दें:
protected $casts = [
'username' => CustomEncrypt::class,
'password' => CustomEncrypt::class,
];
क्योंकि आप क्लास कांस्टेंट (constant) का उपयोग कर रहे हैं, इसलिए ऑटोलोडर बाकी काम संभाल लेता है। यदि आपके एप्लिकेशन को बाद में एन्क्रिप्शन स्कीम बदलने की आवश्यकता होती है, तो आप केवल एक फ़ाइल संपादित करते हैं, और प्रत्येक मैप किया गया फ़ील्ड तुरंत अपना व्यवहार बदल देता है। जब आप कई टेबल्स में संवेदनशील डेटा का प्रबंधन कर रहे हों, तो इस केंद्रीकरण (centralization) का मुकाबला करना कठिन है।
विधि 2: एक्सेसॉर (Accessor) और म्यूटेटर (Mutator) का उपयोग करें
कभी-कभी आप ऐसे ट्रांसफॉर्मेशन के लिए नई फ़ाइल नहीं चाहते जो केवल एक ही जगह मायने रखता हो। Laravel की Attribute क्लास आपको PHP 8+ क्लोजर (closure) सिंटैक्स का उपयोग करके सीधे मॉडल पर get और set लॉजिक को परिभाषित करने की अनुमति देती है।
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function username(): Attribute
{
return Attribute::make(
get: fn ($value) => decrypt_data($value),
set: fn ($value) => encrypt_data($value),
);
}
यहाँ मेथड का नाम उस कॉलम या एट्रिब्यूट से मेल खाना चाहिए जिसे आप लक्षित कर रहे हैं। जब Eloquent डेटाबेस से username पढ़ता है, तो यह कच्ची वैल्यू को get क्लोजर के माध्यम से पास करता है। जब आप मॉडल की username प्रॉपर्टी को एक नई वैल्यू असाइन करते हैं, तो set क्लोजर Eloquent द्वारा क्वेरी बनाने से पहले उसे एन्क्रिप्ट कर देता है।
यह दृष्टिकोण प्रोटोटाइप या लेगेसी (legacy) मॉडल्स में बेहतरीन काम करता है जहाँ कास्ट क्लासेस की एक पूरी डायरेक्टरी बनाना ज़रूरत से ज़्यादा (overkill) लगता है। इसका नुकसान दोहराव (repetition) है। यदि आप बाद में निर्णय लेते हैं कि email, phone, और backup_code को भी उसी तरह के ट्रीटमेंट की आवश्यकता है, तो आप उन क्लोजर्स
दोनों में से किसी एक का चुनाव करना
कस्टम कास्ट क्लास (custom cast class) का उपयोग तब करें जब आप पुन: उपयोग (reuse), टेस्टिंग और मॉडल्स को स्लिम रखने पर ध्यान देना चाहते हैं। यह अन्य डेवलपर्स को संकेत देता है कि यह ट्रांसफॉर्मेशन आपके एप्लिकेशन में एक प्राथमिक (first-class) कॉन्सेप्ट है, न कि कोई अस्थायी जुगाड़ (one-off hack)।
एक्सेसॉर (accessor) का उपयोग तब करें जब लॉजिक वास्तव में स्थानीयकृत (localized), प्रयोगात्मक (experimental) हो, या इसकी संभावना कम हो कि यह वर्तमान स्प्रिंट से आगे तक चलेगा। यह आपको कोडबेस में छोटी-छोटी फ़ाइलों को बिखेरे बिना तेज़ी से काम करने की अनुमति देता है। बस एक बार जब वही पैटर्न दूसरी या तीसरी बार दिखाई दे, तो उसे कास्ट क्लास में रिफैक्टर करने के लिए तैयार रहें।
ध्यान रखने योग्य व्यावहारिक विवरण
कस्टम कास्ट्स शक्तिशाली होते हैं, लेकिन वे ऐसा व्यवहार ला सकते हैं जो यदि आप ध्यान न दें तो आपको चौंका सकते हैं। सबसे पहले, याद रखें कि get को वही प्राप्त होता है जो डेटाबेस ने लौटाया है, जिसमें null भी शामिल है। यदि decrypt_data नल (null) इनपुट को स्वीकार नहीं करता है, तो इससे बचाव का प्रबंध करें:
public function get(Model $model, string $key, mixed $value, array $attributes): mixed
{
return is_null($value) ? null : decrypt_data($value);
}
दूसरा, कास्ट्स ऐरे (array) और JSON सीरियलाइजेशन के दौरान चलते हैं। जब आप किसी मॉडल को API रिसोर्स के रूप में लौटाते हैं या toArray() कॉल करते हैं, तब भी कास्ट get लॉजिक लागू होता है। आमतौर पर आप यही चाहते हैं, लेकिन यदि आप डिक्रिप्ट किए गए मानों (decrypted values) को प्रदर्शित कर रहे हैं और उन पर अतिरिक्त विज़िबिलिटी कंट्रोल लगाने की आवश्यकता है, तो इसे याद रखना महत्वपूर्ण है।
तीसरा, और सबसे महत्वपूर्ण बात यह है कि कास्टिंग डेटा प्राप्त करने के बाद होती है। आप ट्रांसफॉर्म किए गए मान के विरुद्ध क्वेरी नहीं कर सकते। User::where('username', 'john_doe')->first() जैसी क्वेरी स्ट्रिंग john_doe को सीधे डेटाबेस में भेजती है। यह आपके डिक्रिप्ट लॉजिक से कभी नहीं गुजरती है। यदि कॉलम 'एट रेस्ट' (at rest) एन्क्रिप्टेड है, तो वह क्वेरी कुछ भी नहीं खोज पाएगी जब तक कि आप स्वयं एन्क्रिप्टेड सिफरटेक्स्ट (ciphertext) के विरुद्ध खोज न करें। अपने डेटाबेस एक्सेस पैटर्न की योजना उसी के अनुसार बनाएं, क्योंकि कास्ट्स नेटिव डेटाबेस फ़ंक्शंस या इंडेक्स्ड प्लेनटेक्स्ट कॉलम का विकल्प नहीं हैं।
कस्टम कास्ट क्लास कॉन्फ़िगरेशन के छोटे हिस्सों के लिए भी बेहतरीन जगह हैं। यदि आपको कंस्ट्रक्टर आर्गुमेंट्स की आवश्यकता है—जैसे कि साइफर मोड या फॉर्मेट स्ट्रिंग पास करना—तो Laravel उन्हें $casts ऐरे के माध्यम से 'field' => CustomEncrypt::class . ':arg' जैसे एक्सप्रेशन का उपयोग करके सपोर्ट करता है, हालांकि यह यहाँ वर्णित बुनियादी सेटअप से एक कदम आगे है।
वास्तविक निष्कर्ष
$casts में सीधे हेल्पर फ़ंक्शंस डालने पर प्रतिबंध कोई मनमानी नौकरशाही नहीं है। यह आपको ऐसे कोड की ओर ले जाता है जो स्पष्ट (explicit), टेस्ट करने योग्य (testable) और पुन: प्रयोज्य (reusable) है। कस्टम कास्ट क्लास बिखरे हुए इनलाइन लॉजिक को भरोसेमंद कंपोनेंट्स में बदल देती है जिन्हें आप बिना डुप्लीकेशन के विभिन्न मॉडल्स में साझा कर सकते हैं। एक्सेसर्स (accessors) त्वरित, स्थानीयकृत सुधारों के लिए रास्ता खुला रखते हैं जब एक अलग फ़ाइल बनाना अनावश्यक औपचारिकता (ceremony) जैसा लगता है। दोनों में महारत हासिल करें, समस्या के दायरे के आधार पर चुनाव करें, और आपका Eloquent लेयर एप्लिकेशन के बढ़ने के बाद भी लंबे समय तक पठनीय बना रहेगा।
