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

lara8818's avatar

Using IoC within Models

Hey guys,

I'm currently working on de-coupling some heavily coupled code and would like an opinion on the following...

I have a User model that has several direct references to the Stripe SDK. I've added some pseudo code below for a quick example of its present functionality:

class User extends Model {

  /**
   * Cached customer object
   *
   * @var Stripe\Customer
   */
  protected $_customer;

  /**
   * Returns the user's Stripe customer object.
   *
   * @return Stripe\Customer
   */
  public function getCustomerAttribute()
  {
    if ( ! $this->_customer) {
      $this->_customer = Stripe\Customer::retrieve(['id'=>$this->stripe_customer_id]);
    }

    return $this->_customer;
  }
}

As you can see, there is a direct reliance on the static method call to retrieve() on the Stripe\Customer class and it's effectively impossible to mock. Sadly, Eloquent models don't support dependency injection so I have come up with 2 other possible options.

Option 1: Use App::make()

This feels completely wrong to me but the gist is to use App::make() within the model to instantiate the Stripe\Customer. Doing this still allows me the option to replace Stripe\Customer in the DI container.

public function getCustomerAttribute()
{
  if ( ! $this->_customer) {
    $customers = App::make('Stripe\Customer');
    $this->_customer = $customers->retrieve(['id' => $this->stripe_customer_id]);
  }

  return $this->_customer;
}

Option 2: Move billing actions out of the model

The second option is to build one or more custom classes around various billing functions. Then manually pass in the whatever models or data is needed. This would likely lead to some classes like the following:

class StripeGateway implement BillingGateway {
  public function getCustomer(User $user) {
    return Stripe\Customer::retrieve(['id' => $user->stripe_customer_id]);
  }
}

Option 2 feels like a better option to me but there will be a lot of refactor involved if I take that approach.

So what do you guys think is the better option?


0 likes
1 reply
NicoDevs's avatar

Maybe you can pass Stripe\Customer as a dependency when you instantiate the model, something like:

$user = new User(Stripe\Customer $customer);

I also recommend you to use a wrapper class for Stripe\Customer, or (even better) make a class that implements an abstract interface . In the future that will allow you to swap the Stripe\Customer concrete class with some other implementation via that interface.

Please or to participate in this conversation.