Monday, March 20, 2017

How to handle model dependencies inside a Laravel package

I am developing a Laravel package that is meant to be used across multiple Laravel projects. I need to use several Eloquent models within the package but since both the field names and class names might change depending on the consuming app, I am confused about the best way to handle these dependencies within my package.

Some background on the package: the different projects are all ecommerce sites and all have the same common elements such as Products and Orders but the database fields have different names and in some cases the Laravel models are namespaced differently or called different things. I am trying to build a package that can be used by all of these projects to analyze orders and detect potential fraud. Because some of the criteria we are using is checking things like whether or not the person who placed the account has previous order history and whether it was placed on an account, my package needs to have some way of accessing this data. So it needs access to things like an Order model (to check previous order history) and an Account model, but these things might vary depending on the consuming app.

The general API that I want is to be able to use a Fraud facade and have it just work, without requiring the consuming app to add a bunch of code wherever they use this package. Something like this:

$fraud = Fraud::checkOrder($order);
return Fraud::getFraudScore();

I am currently handling this by creating a large config file that informs my package what the name of needed models are in the consuming apps and what their field names are. It looks something like this:

'models' => [
    'order' => [
        'class' => 'App\Order',
        'id' => 'order_id',
        'name' => 'customer_name',
        ...
]

Then in my package class, I can just reference this like so:

protected $orderModel;

public function __construct($options = array())
{
    $this->orderModel = $options['models']['order'];
}

protected function findPreviousOrders()
{
    $order = $this->orderModel['class'];
    $previousOrders = $order::where($this->orderModel['name'], 'Bob')->get();
}

This works but doesn't feel very good to me. It requires a massive config file and doesn't make the code in my package extremely understandable unless you have an intimate knowledge of all the config options. I feel like there is something fundamental I am missing here in terms of model dependencies and package development, but I can't quite figure it out. Any thoughts on a better way to proceed? I'd prefer to require as little code as possible for the consuming apps to use this package.



via Andy Noelker

Advertisement