Laravel ની $casts પ્રોપર્ટી એ એવી શાંત સુવિધાઓમાંની એક છે જે બહુ ધ્યાન ખેંચ્યા વગર તમે ડેટા કેવી રીતે હેન્ડલ કરો છો તેને આકાર આપે છે. એરેમાં boolean અથવા datetime જેવી બિલ્ટ-ઇન ટાઇપ ઉમેરો, અને Eloquent ડેટાબેઝની રો (raw) સ્ટ્રિંગ્સને તમારા કંટ્રોલર્સ અથવા વ્યૂઝ સુધી પહોંચે તે પહેલાં આપમેળે વધુ અનુકૂળ ફોર્મેટમાં રૂપાંતરિત કરી દે છે. તે તમારા કોડને વ્યવસ્થિત રાખે છે. પરંતુ જે ક્ષણે તમે તે એરેની અંદર સીધું તમારું પોતાનું હેલ્પર કોલ કરવાનો પ્રયાસ કરો છો, ત્યારે ફ્રેમવર્ક તેને સ્વીકારતું નથી. 'username' => 'encrypt_data()' જેવું કંઈક લખવાથી કામ નહીં ચાલે. Laravel કાં તો નેટિવ કાસ્ટ કીવર્ડ અથવા CastsAttributes ઇન્ટરફેસને અમલમાં મૂકે છે તેવી ક્લાસની અપેક્ષા રાખે છે. આ જરૂરિયાત એટલા માટે છે કારણ કે કાસ્ટિંગ લેયર Eloquent ના હાઇડ્રેશન (hydration) અને સિરિયલાઇઝેશન (serialization) સાયકલની અંદર ઊંડે સુધી ચાલે છે; તેને રનટાઇમ પર અસ્તિત્વમાં ન હોઈ શકે તેવી કોઈ મનસ્વી ફંક્શન સ્ટ્રિંગને બદલે સ્પષ્ટ કોન્ટ્રાક્ટ ધરાવતા અનુમાનિત ઓબ્જેક્ટની જરૂર હોય છે.

$casts એરેમાં હેલ્પર ફંક્શન્સ કેમ નિષ્ફળ જાય છે

જ્યારે Eloquent મોડલ લોડ કરે છે, ત્યારે તે દરેક કોલમને કેવી રીતે રૂપાંતરિત કરવી તે નક્કી કરવા માટે $casts એરેને સ્કેન કરે છે. ફ્રેમવર્ક ચોક્કસ પ્રિમીટિવ્સ—string, integer, array, encrypted, વગેરે—ને ઓળખે છે અને CastsAttributes ને અમલમાં મૂકે છે તેવા ફૂલી-ક્વોલિફાઇડ ક્લાસ નેમ્સને પણ ઓળખે છે. તે સ્ટ્રિંગને કોડ તરીકે ઇવેલ્યુએટ કરતું નથી. તેથી 'encrypt_data()' ને અજાણ્યા કાસ્ટ ટાઇપ તરીકે ગણવામાં આવે છે, જેનાથી એરર આવે છે. જો Laravel તેને પાર્સ પણ કરે, તો પણ મોડલ ઇન્સ્ટન્સ, એટ્રિબ્યુટ કી, વર્તમાન વેલ્યુ અને આસપાસના એટ્રિબ્યુટ્સને તમારા ફંક્શનમાં યોગ્ય ક્રમમાં પસાર કરવાનો કોઈ વિશ્વસનીય રસ્તો રહેશે નહીં. તમારી કસ્ટમ લોજિક અને Eloquent ના ઇન્ટરનલ્સ વચ્ચેના તે હેન્ડશેકને સ્ટાન્ડર્ડાઇઝ કરવા માટે જ આ ઇન્ટરફેસ અસ્તિત્વ ધરાવે છે.

આ અંતરને પૂરવા માટે તમારી પાસે બે મજબૂત રસ્તાઓ છે. એક લાંબા ગાળાના પુનઃઉપયોગ માટે છે. બીજું ત્યારે ઝડપ આપે છે જ્યારે તમારે ફક્ત એક જ મોડલમાં ઝડપી પેચની જરૂર હોય.

પદ્ધતિ 1: કસ્ટમ કાસ્ટ ક્લાસ લખો

જો સમાન રૂપાંતરણ અનેક ફિલ્ડ્સ પર લાગુ પડતું હોય અથવા અનેક મોડલ્સમાં ફેલાયેલું હોય, તો ડેડિકેટેડ કાસ્ટ ક્લાસ એ વધુ સારો વિકલ્પ છે. તે તેની પોતાની ફાઇલમાં રહે છે, તેને અલગથી યુનિટ-ટેસ્ટ કરી શકાય છે, અને તે તમારા મોડલ્સને વારંવારના બોઇલરપ્લેટ કોડથી મુક્ત રાખે છે.

app/Casts/CustomEncrypt.php બનાવીને શરૂઆત કરો. નેમસ્પેસ તમારા ઓટોલોડિંગ સેટઅપ સાથે મેળખતું હોવું જોઈએ, સામાન્ય રીતે 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);
    }
}

સિગ્નેચર્સ મહત્વના છે. Eloquent દરેક મેથડમાં ચાર આર્ગ્યુમેન્ટ્સ પસાર કરે છે. $model એ જે ઇન્સ્ટન્સ ભરાઈ રહ્યો છે અથવા સેવ થઈ રહ્યો છે તે છે, જે તમને અન્ય ફિલ્ડ્સ તપાસવાની મંજૂરી આપે છે જો તમારું લોજિક તેના પર આધારિત હોય. $key એ હાલમાં કાસ્ટ થઈ રહેલા કોલમનું નામ છે. $valueget વખતે ડેટાબેઝમાંથી આવતી રો (raw) સ્ટ્રિંગ અથવા નલ (null) છે, અથવા set વખતે યુઝર દ્વારા આપવામાં આવેલી વેલ્યુ છે. $attributes એ તે રો માટેના તમામ કોલમ્સનો રો (raw) એરે છે. તમારે દર વખતે ચારેયનો ઉપયોગ કરવાની જરૂર નથી, પરંતુ ઇન્ટરફેસ તેને જરૂરી બનાવે છે.

ઉપરની get મેથડમાં, decrypt_data($value) Eloquent ડેટાબેઝમાંથી રો ફેચ કરે તે પછી અને વેલ્યુ તમારા મોડલ પર પહોંચે તે પહેલાં ચાલે છે. set મેથડમાં, encrypt_data($value) INSERT અથવા UPDATE પહેલાં ચાલે છે, જે સુનિશ્ચિત કરે છે કે ડેટાબેઝ ક્યારેય પ્લેનટેક્સ્ટ ન જુએ.

તેને જોડવા માટે, તમારા મોડલના $casts એરેની અંદર ક્લાસનો સંદર્ભ આપો:

protected $casts = [
    'username' => CustomEncrypt::class,
    'password' => CustomEncrypt::class,
];

કારણ કે તમે ક્લાસ કોન્સ્ટન્ટનો ઉપયોગ કરી રહ્યા છો, ઓટોલોડર બાકીનું કામ સંભાળી લે છે. જો તમારા એપ્લિકેશનને પછીથી એન્ક્રિપ્શન સ્કીમ બદલવાની જરૂર પડે, તો તમે ફક્ત એક ફાઇલ એડિટ કરો છો, અને દરેક મેપ્ડ ફિલ્ડનું વર્તન તરત જ બદલાઈ જાય છે. જ્યારે તમે અનેક ટેબલ્સમાં સંવેદનશીલ ડેટાનું સંચાલન કરી રહ્યા હોવ ત્યારે આ સેન્ટ્રલાઇઝેશનને પછાડવું મુશ્કેલ છે.

પદ્ધતિ 2: એક્સેસર અને મ્યુટેટરનો ઉપયોગ કરો

ક્યારેક તમે એવા રૂપાંતરણ માટે નવી ફાઇલ બનાવવા માંગતા નથી જે ફક્ત એક જ જગ્યાએ મહત્વનું હોય. Laravel ની Attribute ક્લાસ તમને PHP 8+ ક્લોઝર સિન્ટેક્સનો ઉપયોગ કરીને સીધું મોડલ પર જ 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 ક્લોઝર દ્વારા રો (raw) વેલ્યુ પસાર કરે છે. જ્યારે તમે મોડલની username પ્રોપર્ટીને નવી વેલ્યુ અસાઇન કરો છો, ત્યારે Eloquent ક્વેરી બનાવતા પહેલા set ક્લોઝર તેને એન્ક્રિપ્ટ કરે છે.

આ અભિગમ પ્રોટોટાઇપ્સ અથવા લેગસી મોડલ્સમાં શ્રેષ્ઠ છે જ્યાં કાસ્ટ ક્લાસની આખી ડિરેક્ટરી બનાવવી એ જરૂરિયાત કરતા વધારે લાગે છે. તેનો ગેરફાયદો પુનરાવર્તન છે. જો તમે પછીથી નક્કી કરો છો કે email, phone, અને backup_code ને સમાન ટ્રીટમેન્ટની જરૂર છે, તો તમારે તે ક્લોઝર્સને અનેક મેથડ્સ અથવા મોડલ્સમાં કોપી કરવા પડશે. આ વધારાનો કોડ વધી જાય છે. તે તમને આખા મોડલને બૂટ કર્યા વગર યુનિટ ટેસ્ટમાં લોજિકનો પુનઃઉપયોગ કરતા પણ અટકાવે છે.

બે વચ્ચે પસંદગી કરવી

જ્યારે તમે પુનઃઉપયોગ (reuse), ટેસ્ટિંગ અને મોડલ્સને સ્લિમ રાખવા વિશે ચિંતિત હોવ ત્યારે કસ્ટમ કાસ્ટ ક્લાસ (custom cast class) નો ઉપયોગ કરો. તે અન્ય ડેવલપર્સને સંકેત આપે છે કે આ રૂપાંતરણ તમારા એપ્લિકેશનમાં એક 'ફર્સ્ટ-ક્લાસ કોન્સેપ્ટ' છે, કોઈ વન-ઓફ હેક (one-off hack) નથી.

જ્યારે લોજિક ખરેખર સ્થાનિક (localized), પ્રાયોગિક હોય અથવા વર્તમાન સ્પ્રિન્ટ (sprint) પછી ટકી રહેવાની શક્યતા ઓછી હોય ત્યારે એક્સેસર (accessor) નો ઉપયોગ કરો. તે તમને કોડબેઝમાં નાની ફાઇલો વિખેરી નાખ્યા વગર ઝડપથી આગળ વધવા દે છે. બસ, જ્યારે સમાન પેટર્ન બીજી કે ત્રીજી વાર દેખાય ત્યારે તેને કાસ્ટ ક્લાસમાં રિફેક્ટર (refactor) કરવા માટે તૈયાર રહો.

ધ્યાનમાં રાખવા જેવી વ્યવહારિક વિગતો

કસ્ટમ કાસ્ટ શક્તિશાળી છે, પરંતુ જો તમે ધ્યાન ન આપો તો તે એવા વર્તન (behavior) રજૂ કરી શકે છે જે તમને આશ્ચર્યચકિત કરી શકે છે. પ્રથમ, યાદ રાખો કે 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 સિરિયલાઈઝેશન (serialization) દરમિયાન ચાલે છે. જ્યારે તમે મોડલને API રિસોર્સ તરીકે રિટર્ન કરો છો અથવા toArray() કોલ કરો છો, ત્યારે કાસ્ટ get લોજિક હજુ પણ લાગુ થાય છે. સામાન્ય રીતે તમે આ જ ઈચ્છતા હોવ છો, પરંતુ જો તમે ડિક્રિપ્ટ કરેલી કિંમતો એક્સપોઝ કરી રહ્યા હોવ અને તેના પર વધારાના વિઝિબિલિટી કંટ્રોલ્સ (visibility controls) લગાવવાની જરૂર હોય, તો આ યાદ રાખવું યોગ્ય છે.

ત્રીજું, અને સૌથી મહત્વનું, કાસ્ટિંગ ડેટા મેળવ્યા પછી થાય છે. તમે રૂપાંતરિત કિંમત સામે ક્વેરી (query) કરી શકતા નથી. User::where('username', 'john_doe')->first() જેવી ક્વેરી સ્ટ્રિંગ john_doe ને સીધી ડેટાબેઝમાં મોકલે છે. તે ક્યારેય તમારા ડિક્રિપ્ટ લોજિકમાંથી પસાર થતી નથી. જો કોલમ 'એનક્રિપ્ટેડ એટ રેસ્ટ' (encrypted at rest) હોય, તો જ્યાં સુધી તમે પોતે એનક્રિપ્ટેડ સાઇફરટેક્સ્ટ (ciphertext) સામે સર્ચ ન કરો ત્યાં સુધી તે ક્વેરી કંઈ જ શોધી શકશે નહીં. તમારા ડેટાબેઝ એક્સેસ પેટર્નને તે મુજબ પ્લાન કરો, કારણ કે કાસ્ટ નેટિવ ડેટાબેઝ ફંક્શન્સ અથવા ઇન્ડેક્સ કરેલા પ્લેનટેક્સ્ટ કોલમ્સનો વિકલ્પ નથી.

કસ્ટમ કાસ્ટ ક્લાસ કોન્ફિગરેશનના નાના ભાગો માટે પણ ઉત્તમ હોઈ શકે છે. જો તમારે કન્સ્ટ્રક્ટર આર્ગ્યુમેન્ટ્સ (constructor arguments) ની જરૂર હોય—કદાચ સાઇફર મોડ અથવા ફોર્મેટ સ્ટ્રિંગ પસાર કરવા માટે—તો Laravel તેને $casts એરે દ્વારા 'field' => CustomEncrypt::class . ':arg' જેવા એક્સપ્રેશનનો ઉપયોગ કરીને સપોર્ટ કરે છે, જોકે તે અહીં વર્ણવેલા મૂળભૂત સેટઅપથી એક સ્ટેપ આગળનું છે.

મુખ્ય સારાંશ

$casts માં સીધા હેલ્પર ફંક્શન્સ ઉમેરવા પરનું પ્રતિબંધ એ કોઈ મનસ્વી અમલદારશાહી નથી. તે તમને એવા કોડ તરફ દોરી જાય છે જે સ્પષ્ટ (explicit), ટેસ્ટેબલ (testable) અને પુનઃઉપયોગી (reusable) હોય. કસ્ટમ કાસ્ટ ક્લાસ વિખરાયેલા ઇનલાઇન લોજિકને વિશ્વસનીય ઘટકોમાં ફેરવે છે જેને તમે ડુપ્લીકેશન વગર વિવિધ મોડલ્સમાં શેર કરી શકો છો. જ્યારે અલગ ફાઇલ બનાવવી બિનજરૂરી લાગે ત્યારે એક્સેસર્સ ઝડપી અને સ્થાનિક ફિક્સ માટે તક પૂરી પાડે છે. બંનેમાં નિપુણતા મેળવો, સમસ્યાના વ્યાપના આધારે પસંદગી કરો, અને એપ્લિકેશન વધ્યા પછી પણ તમારું Eloquent લેયર વાંચવા યોગ્ય રહેશે.