I'm trying to refactor my project from having all code under the App folder into seperate composer packages. However I've hit a blocker which I could use some input to solve:
To simplify I'd like to create 2 packages, Core
and Customers
. I want Core
to be fully seperated, having no references to any of my other packages. Inside Core
there is a model called Business
, and in Customer
there is a model called Customer
. There is a many-to-one relation ship between the models. The problem arises when I want to create the Eloquent relationship methods. Customer
is dependant on Core
, so this is not an issue, $this->belongsTo(Business::class)
. However, to get the inverse Core
needs to know about the Customer
model, $this->hasMany(Customer::class)
.
Is there a way around this? Like maybe registering a method on the Business
model from my Customer
package? Or have I gotten it all backwards?
EDIT
For those not familiar with Laravel, a relationship is defined as a function in the model class
class Business extends Model {
public function customers() {
return $this->hasMany(Customer::class);
}
}
How most people do this is dependency injection, but that's more of a service type thing and less of a model relationship type thing. As you have it now I can think of a couple options.
Dependency inject your relationship using an enum or registry
class Business extends Model {
public function customers() {
return $this->hasMany(ModelEnum::byName('Customers')->class());
}
}
or
class Business extends Model {
public function customers() {
$models = collect(get_declared_classes())->filter(function ($item) {
$item == 'YOURPACKAGENAME\Models\\Customers' ? $item : throw new Exception();
return $item
});
return $this->hasMany($item);
}
}
I think the best thing though would be to either add or remove the class(es), Having an intra package model kinda defeats the purpose of seperating you code with packages.
Two possible solutions:
Just declare relation directly and throw exception if class does not exist:
public function customers() {
if (class_exists(Customer::class)) {
throw new \SomeException();
}
return $this->hasMany(Customer::class);
}
::class
does not trigger autoloading, so it could be used even if class is not available. This will still create dependency on Customers
, but at least it will be optional.
Customers
package could provide Business
with proper relation. So if you want to use Business
class with Customers
, you should use Customers\Models\Business
instead of Core\Models\Business
:
class Business extends \Core\Models\Business {
public function customers() {
return $this->hasMany(Customer::class);
}
}
This will keep Core
free from dependency on Customers
, but it does not scale at all (you can't have second package which will do the same with Business
class).