Elevate Your Laravel Models with Custom Object Casting

Elevate Your Laravel Models with Custom Object Casting

Laravel's Eloquent ORM offers powerful features for working with databases, and custom object casting is one of the gems that can significantly enhance your data handling. This feature allows you to transform your model attributes into complex objects, providing a clean and intuitive way to work with structured data.

Implementing Custom Object Casting

To create a custom cast, you need to implement the CastsAttributes interface. Here's how you can do it:

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class Address implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return new AddressValueObject(
            $attributes['address_line_one'],
            $attributes['address_line_two']
        );
    }

    public function set($model, $key, $value, $attributes)
    {
        return [
            'address_line_one' => $value->lineOne,
            'address_line_two' => $value->lineTwo,
        ];
    }
}

Real-World Example: E-commerce Customer Management

Let's consider an e-commerce platform where we need to handle customer addresses. We'll create a custom Address cast to manage this complex data structure.

First, let's define our AddressValueObject:

class AddressValueObject implements JsonSerializable
{
    public function __construct(
        public string $lineOne,
        public string $lineTwo,
        public string $city,
        public string $state,
        public string $postalCode,
        public string $country
    ) {}

    public function jsonSerialize()
    {
        return get_object_vars($this);
    }

    public function fullAddress(): string
    {
        return "{$this->lineOne}, {$this->lineTwo}, {$this->city}, {$this->state} {$this->postalCode}, {$this->country}";
    }
}

Now, let's create our custom Address cast:

class Address implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return new AddressValueObject(
            $attributes['address_line_one'],
            $attributes['address_line_two'],
            $attributes['city'],
            $attributes['state'],
            $attributes['postal_code'],
            $attributes['country']
        );
    }

    public function set($model, $key, $value, $attributes)
    {
        return [
            'address_line_one' => $value->lineOne,
            'address_line_two' => $value->lineTwo,
            'city' => $value->city,
            'state' => $value->state,
            'postal_code' => $value->postalCode,
            'country' => $value->country,
        ];
    }
}

Now we can use this custom cast in our Customer model:

class Customer extends Model
{
    protected $casts = [
        'address' => Address::class,
    ];
}

Here's how we can use this in our application:

class CustomerController extends Controller
{
    public function update(Request $request, Customer $customer)
    {
        $customer->address = new AddressValueObject(
            $request->input('address_line_one'),
            $request->input('address_line_two'),
            $request->input('city'),
            $request->input('state'),
            $request->input('postal_code'),
            $request->input('country')
        );

        $customer->save();

        return response()->json([
            'message' => 'Customer updated successfully',
            'full_address' => $customer->address->fullAddress(),
        ]);
    }

    public function show(Customer $customer)
    {
        return view('customers.show', [
            'customer' => $customer,
            'fullAddress' => $customer->address->fullAddress(),
        ]);
    }
}

By leveraging custom object casting, you can create more expressive and maintainable code, especially when dealing with complex data structures. This approach is particularly useful for e-commerce platforms, CRM systems, or any application that deals with structured data that doesn't neatly fit into a single database column.

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe