Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

t0berius's avatar

laravel design of code (enum related)

I'm using enums to transform database IDs to "readable" code, inside my enum class I want to perform different checks in the overlaying model:

<?php

namespace App\Enums;

...enum declaration...

public function getOrderStatusBadgeType(Order $order, User $user){
    //seller view
    if($user->id == $order->seller_id){
    
        return match ($this){
            self::AWAITING_PAYMENT => 'some-badge',
            self::PAYMENT_RECEIVED => 'another-badge',
        };

    }
    //buyer views
    elseif ($user->id == $order->buyer_id) {

    }

    //admin view
    else {

    }
}

As far as I know, there's no way to access the overlaying model?

Using the code like:

$order->status_id->getOrderStatusBadgeType($order, Auth::user());

feels total wrong and I'm sure this is not the best way to do so.

0 likes
6 replies
martinbean's avatar

@t0berius I don’t really understand what you mean by “overlaying” model?

If your enum class has methods then pass whatever arguments that method needs to process your logic. So if you want to check a model instance, pass that model instance as a parameter.

t0berius's avatar

@martinbean

As you can see inside my getOrderStatusBadgeType function I need access to the model instance of type Order and access to the current User model.

Is there a better way then just pass them to the enum function itself?

Maybe it just feels strange but somehow I thought there might be a better way to solve this, in all examples I was able to find, there wasn't a need to access any object from inside the enum function.

martinbean's avatar

Is there a better way then just pass them to the enum function itself?

@t0berius No, there isn’t a better way if you wish to stick to the Tell, Don‘t Ask principle (which you should be).

If a piece of code (such as a class or method) needs something to do its job, then that requirement should be passed in. The class/method shouldn’t be “reaching out” and trying to grab things from places it doesn’t know about.

t0berius's avatar

@martinbean Would it be possible for you to provide a bit more words on this like how would you structure this?

From my point of view (as @kokoshneta mentioned too) I shouldn't mix enum functions with external objects.

martinbean's avatar

@t0berius I’d already described the approach?

If you have a method that relies an order model and a user model, then you should pass those models to the method as parameters, instead of the method trying to grab it from outside.

Your code example was fine:

public function getOrderStatusBadgeType(Order $order, User $user)
{
    // Method can use order and user passed in as arguments...
}

By passing dependencies as parameters, you can now easily test this method by providing mocks if you need to, because it’s no longer relying on state or objects outside of the method itself.

kokoshneta's avatar

The reason there isn’t normally a need to do so is that you normally don’t have functions in enums that require knowledge of external objects – there’s rarely a need to do that.

I would argue that it’s also not really necessary here, either. It looks to me as if you’re using the order and user objects to determine the user’s role in relation to the order (buyer, seller or admin) – but the logic of determining that doesn’t belong inside the order status enum. That’s a property of either the order (or perhaps the current user), not the order status. The order status should just receive information about it, rather than containing logic to calculate it.

I would do something like this:

// OrderUserRole enum to determine user’s role
enum OrderUserRole {
	case Buyer;
	case Seller;
	case Admin;
}
// Order class
public function userRole() {
	if ($this->user->id == $this->buyer_id) return OrderUserRole::Buyer;
	if ($this->user->id == $this->seller_id) return OrderUserRole::Seller;
	return OrderUserRole::Admin;
}

public getStatusBadgeType() {
	return $this->status_id->badgeType($this->userRole());
}
// OrderStatus enum
public function badgeType(OrderUserRole $role) {
	switch ($role) {
		case OrderUserRole::Buyer:
			return match ($this) {
				self::AwaitingPayment => 'some-badge',
				self::PaymentReceived => 'another-badge'
			}
		break;

		case OrderUserRole::Seller:
			…
		break;

		case OrderUserRole::Admin:
			…
		break;
	}
}
1 like

Please or to participate in this conversation.