Laravel యొక్క $casts ప్రాపర్టీ అనేది మీరు డేటాను ఎలా హ్యాండిల్ చేస్తారో తెలియజేసే ఒక నిశ్శబ్ద సౌకర్యం. boolean లేదా datetime వంటి బిల్ట్-ఇన్ టైప్‌ను అర్రేలో చేర్చినప్పుడు, Eloquent ఆటోమేటిక్‌గా డేటాబేస్ నుండి వచ్చే రా (raw) స్ట్రింగ్స్‌ను మీ కంట్రోలర్లు లేదా వ్యూస్‌కు చేరే ముందే సులభంగా అర్థమయ్యే ఫార్మాట్‌లోకి మారుస్తుంది. ఇది మీ కోడ్‌ను నీట్‌గా ఉంచుతుంది. కానీ మీరు ఆ అర్రేలో నేరుగా మీ స్వంత హెల్పర్ ఫంక్షన్‌ను పిలవాలని ప్రయత్నించినప్పుడు, ఫ్రేమ్‌వర్క్ అడ్డుకుంటుంది. 'username' => 'encrypt_data()' వంటి కోడ్ పనిచేయదు. Laravel ఒక నేటివ్ కాస్ట్ కీవర్డ్ లేదా CastsAttributes ఇంటర్‌ఫేస్‌ను ఇంప్లిమెంట్ చేసే క్లాస్‌ను ఆశిస్తుంది. ఈ అవసరం ఎందుకంటే కాస్టింగ్ లేయర్ Eloquent యొక్క హైడ్రేషన్ మరియు సీరియలైజేషన్ సైకిల్‌లో లోతుగా ఉంటుంది; దానికి రన్‌టైమ్‌లో ఉండకపోవచ్చని అనుమానించే ఏదైనా రాండమ్ ఫంక్షన్ స్ట్రింగ్ కంటే, స్పష్టమైన కాంట్రాక్ట్‌తో కూడిన ప్రిడిక్టబుల్ ఆబ్జెక్ట్ అవసరం.

$casts అర్రేలో హెల్పర్ ఫంక్షన్‌లు ఎందుకు విఫలమవుతాయి

Eloquent ఒక మోడల్‌ను లోడ్ చేసినప్పుడు, ప్రతి కాలమ్‌ను ఎలా మార్చాలో నిర్ణయించడానికి $casts అర్రేను స్కాన్ చేస్తుంది. ఫ్రేమ్‌వర్క్ string, integer, array, encrypted వంటి నిర్దిష్ట ప్రిమిటివ్‌లను మరియు CastsAttributesను ఇంప్లిమెంట్ చేసే ఫుల్లీ-క్వాలిఫైడ్ క్లాస్ పేర్లను గుర్తిస్తుంది. ఇది ఆ స్ట్రింగ్‌ను కోడ్‌గా పరిగణించదు. కాబట్టి 'encrypt_data()' అనేది తెలియని కాస్ట్ టైప్‌గా పరిగణించబడుతుంది, ఇది ఎర్రర్‌కు దారితీస్తుంది. ఒకవేళ Laravel దానిని పార్స్ చేసినా, మోడల్ ఇన్‌స్టెన్స్, ఆట్రిబ్యూట్ కీ, ప్రస్తుత విలువ మరియు చుట్టూ ఉన్న ఆట్రిబ్యూట్‌లను సరైన క్రమంలో మీ ఫంక్షన్‌కు పంపడానికి నమ్మకమైన మార్గం ఉండదు. మీ కస్టమ్ లాజిక్ మరియు Eloquent ఇంటర్నల్స్ మధ్య ఆ హ్యాండ్‌షేక్‌ను స్టాండర్డైజ్ చేయడానికి ఈ ఇంటర్‌ఫేస్ ఉద్దేశించబడింది.

మీకు ఈ సమస్యను పరిష్కరించడానికి రెండు పద్ధతులు ఉన్నాయి. ఒకటి దీర్ఘకాలిక పునర్వినియోగం (reuse) కోసం ఉపయోగపడుతుంది. రెండవది, ఒకే మోడల్‌లో త్వరగా పరిష్కరించుకోవాలనుకున్నప్పుడు వేగంగా పనిచేస్తుంది.

పద్ధతి 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 అనేది ప్రస్తుతం కాస్ట్ చేయబడుతున్న కాలమ్ పేరు. $value అనేది get చేసినప్పుడు డేటాబేస్ నుండి వచ్చే రా స్ట్రింగ్ లేదా నల్ (null), లేదా set చేసినప్పుడు యూజర్ అందించిన విలువ. $attributes అనేది ఆ రో (row) యొక్క మొత్తం రా కాలమ్స్ అర్రే. మీరు ప్రతిసారీ ఈ నాలుగింటినీ ఉపయోగించాల్సిన అవసరం లేదు, కానీ ఇంటర్‌ఫేస్ వాటిని కోరుతుంది.

పైన ఉన్న get మెథడ్‌లో, Eloquent డేటాబేస్ నుండి రోను తీసుకున్న తర్వాత మరియు విలువ మీ మోడల్‌కు చేరకముందే decrypt_data($value) రన్ అవుతుంది. set మెథడ్‌లో, encrypt_data($value) అనేది INSERT లేదా UPDATE కంటే ముందే రన్ అవుతుంది, తద్వారా డేటాబేస్‌లో ఎప్పుడూ ప్లెయిన్ టెక్స్ట్ కనిపించదు.

దీనిని ఉపయోగించడానికి, మీ మోడల్ యొక్క $casts అర్రేలో క్లాస్‌ను రిఫరెన్స్ చేయండి:

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

మీరు క్లాస్ కాన్స్టెంట్‌ను ఉపయోగిస్తున్నందున, ఆటోలోడర్ మిగిలిన పనిని చూసుకుంటుంది. మీ అప్లికేషన్‌కు తర్వాత ఎన్‌క్రిప్షన్ స్కీమ్‌ను మార్చాల్సి వస్తే, మీరు ఒకే ఒక ఫైల్‌ను ఎడిట్ చేస్తే సరిపోతుంది, అప్పుడు మ్యాప్ చేయబడిన ప్రతి ఫీల్డ్ వెంటనే మారుతుంది. అనేక టేబుల్స్‌లో సెన్సిటివ్ డేటాను మేనేజ్ చేస్తున్నప్పుడు ఈ సెంట్రలైజేషన్ చాలా ఉపయోగకరంగా ఉంటుంది.

పద్ధతి 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 ప్రాపర్టీకి కొత్త విలువను కేటాయించినప్పుడు, Eloquent క్వెరీని నిర్మించే ముందే set క్లోజర్ దానిని ఎన్‌క్రిప్ట్ చేస్తుంది.

ఈ విధానం ప్రోటోటైప్‌లు లేదా పూర్తి డైరెక్టరీ ఆఫ్ కాస్ట్ క్లాస్‌లు అవసరం లేని లెగసీ మోడల్స్‌లో బాగా పనిచేస్తుంది. దీని లోపం ఏమిటంటే పదేపదే రాయాల్సి రావడం (repetition). ఒకవేళ మీరు తర్వాత email, phone, మరియు backup_codeలకు కూడా ఇదే ట్రీట్‌మెంట్ కావాలని నిర్ణయించుకుంటే, మీరు ఆ క్లోజర్‌లను బహుళ మెథడ్‌లు లేదా మోడల్స్‌లో కాపీ చేయాల్సి వస్తుంది. ఇది కోడ్‌ను అనవసరంగా పెంచుతుంది. అలాగే, పూర్తి మోడల్‌ను బూట్ చేయకుండా యూనిట్ టెస్ట్‌లో ఈ లాజిక్‌ను తిరిగి ఉపయోగించకుండా ఇది అడ్డుకుంటుంది.

ఈ రెండింటి మధ్య ఎంపిక చేసుకోవడం

మీరు పునర్వినియోగం (reuse), టెస్టింగ్ మరియు మోడల్స్‌ను సరళంగా (slim) ఉంచడంపై దృష్టి పెట్టినప్పుడు కస్టమ్ కాస్ట్ క్లాస్‌ను ఉపయోగించండి. ఈ మార్పిడి (transformation) అనేది మీ అప్లికేషన్‌లో ఒక ప్రాథమిక భావన అని, కేవలం ఒక తాత్కాలిక పరిష్కారం (one-off hack) కాదని ఇది ఇతర డెవలపర్‌లకు తెలియజేస్తుంది.

లాజిక్ పూర్తిగా స్థానికంగా (localized) ఉన్నప్పుడు, ప్రయోగాత్మకంగా ఉన్నప్పుడు లేదా ప్రస్తుత స్ప్రింట్ కంటే ఎక్కువ కాలం ఉండకపోవచ్చు అని అనిపించినప్పుడు యాక్సెసర్‌ను ఉపయోగించండి. ఇది కోడ్‌బేస్ అంతటా చిన్న ఫైళ్లను చెల్లాచెదురు చేయకుండా వేగంగా ముందుకు వెళ్లడానికి అనుమతిస్తుంది. అదే ప్యాటర్న్ రెండో లేదా మూడోసారి కనిపించినప్పుడు, దానిని కాస్ట్ క్లాస్‌గా రీఫ్యాక్టర్ (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);
}

రెండవది, కాస్ట్‌లు అర్రే మరియు JSON సీరియలైజేషన్ సమయంలో రన్ అవుతాయి. మీరు ఒక మోడల్‌ను API రిసోర్స్‌గా తిరిగి పంపినప్పుడు లేదా toArray()ని కాల్ చేసినప్పుడు, కాస్ట్ get లాజిక్ ఇంకా వర్తిస్తుంది. సాధారణంగా మీకు కావాల్సింది ఇదే, కానీ మీరు డీక్రిప్ట్ చేసిన విలువలను ఎక్స్‌పోజ్ చేస్తున్నప్పుడు మరియు వాటిపై అదనపు విజిబిలిటీ కంట్రోల్స్‌ను జోడించాల్సిన అవసరం ఉన్నప్పుడు దీనిని గుర్తుంచుకోవడం ముఖ్యం.

మూడవది, మరియు అన్నిటికంటే ముఖ్యమైనది, కాస్టింగ్ అనేది డేటాను పొందిన తర్వాత జరుగుతుంది. మీరు మార్చబడిన విలువపై (transformed value) క్వెరీ చేయలేరు. User::where('username', 'john_doe')->first() వంటి క్వెరీ నేరుగా john_doe అనే స్ట్రింగ్‌ను డేటాబేస్‌కు పంపుతుంది. ఇది మీ డీక్రిప్ట్ లాజిక్ ద్వారా ఎప్పుడూ వెళ్లదు. ఒకవేళ కాలమ్ ఎన్‌క్రిప్ట్ చేయబడి ఉంటే, మీరు ఎన్‌క్రిప్ట్ చేయబడిన సైఫర్‌టెక్స్ట్ (ciphertext) ద్వారా వెతకకపోతే, ఆ క్వెరీ ఏమీ కనుగొనదు. మీ డేటాబేస్ యాక్సెస్ ప్యాటర్న్‌లను దానికి అనుగుణంగా ప్లాన్ చేయండి, ఎందుకంటే కాస్ట్‌లు నేటివ్ డేటాబేస్ ఫంక్షన్‌లకు లేదా ఇండెక్స్ చేయబడిన ప్లెయిన్ టెక్స్ట్ కాలమ్స్‌కు ప్రత్యామ్నాయం కాదు.

కస్టమ్ కాస్ట్ క్లాస్‌లు చిన్న చిన్న కాన్ఫిగరేషన్ల కోసం కూడా అద్భుతమైన వేదికలు. మీకు కన్స్ట్రక్టర్ ఆర్గ్యుమెంట్స్ అవసరమైతే—బహుశా సైఫర్ మోడ్ లేదా ఫార్మాట్ స్ట్రింగ్‌ను పంపడం వంటివి—Laravel వాటిని $casts అర్రే ద్వారా 'field' => CustomEncrypt::class . ':arg' వంటి ఎక్స్‌ప్రెషన్‌ను ఉపయోగించి సపోర్ట్ చేస్తుంది, అయితే ఇది ఇక్కడ వివరించిన ప్రాథమిక సెటప్ కంటే ఒక అడుగు ముందుకు వెళ్ళిన విషయం.

అసలైన సారాంశం

$casts లో నేరుగా హెల్పర్ ఫంక్షన్లను ఉపయోగించకూడదనే నిబంధన అనేది కేవలం ఒక అనవసరమైన నిబంధన కాదు. ఇది మిమ్మల్ని స్పష్టమైన, టెస్టబుల్ మరియు పునర్వినియోగపరచదగిన కోడ్ వైపు నడిపిస్తుంది. కస్టమ్ కాస్ట్ క్లాస్‌లు చెల్లాచెదురుగా ఉన్న ఇన్‌లైన్ లాజిక్‌ను, డూప్లికేషన్ లేకుండా మీరు మోడల్స్ అంతటా పంచుకోగల నమ్మదగిన భాగాలగా (dependable components) మారుస్తాయి. ఒక ప్రత్యేక ఫైల్ సృష్టించడం అనవసరమైన పనిగా అనిపించినప్పుడు, త్వరితగతిన, స్థానికంగా పరిష్కరించుకోవడానికి యాక్సెసర్‌లు మార్గాన్ని సుగమం చేస్తాయి. రెండింటినీ నేర్చుకోండి, సమస్య యొక్క పరిధిని బట్టి ఎంచుకోండి, తద్వారా మీ అప్లికేషన్ పెరిగిన తర్వాత కూడా మీ Eloquent లేయర్ చదవడానికి సులభంగా ఉంటుంది.