@noblemfd In that case, I’d look to create some interfaces that represents what it is your application does; regardless of the company. So if your application fetches a list of employees for a company, then you might have an EmployeeRepository interface, and various implementations of that interface, i.e. DatabaseEmployeeRepository, AzureEmployeeRepository, etc. This is so that, no matter what data source your company uses, your application code remains the same, and even brand new data sources can be introduced at a later data without having to change any of your application’s business logic if it’s just working against interfaces and not concrete implementations.
In terms of selecting the appropriate implementation, there are a couple of ways you could do this. One could be to identify the company in the request (if you’re using route parameters), and then maybe use middleware to bind the correct implementation in the container at runtime:
class ConfigureCompanyServices
{
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
public function handle($request, Closure $next)
{
$company = $request->route('company'); // Gets company if in route, i.e. /companies/{company}
$this->container->singleton(EmployeeRepositoryContract::class, function () use ($company) {
switch ($company->data_source_type) {
case 'azure':
// return new instance of AzureEmployeeRepository
case 'database':
// return new instance of DatabaseEmployeeRepository
default:
throw new InvalidArgumentException(
sprintf('Unsupported data source type: %s', $company->data_source_type)
);
}
});
return $next($request);
}
}
With an implementation bound in the container, you’ll then be able to type-hint the repository interface in your classes to get the correct implementation:
class EmployeeController
{
protected $employeeRepository;
public function __construct(EmployeeRepository $employeeRepository)
{
$this->employeeRepository = $employeeRepository;
}
}
Alternatively, you could just have methods on your Company model that return the appropriate implementation on demand:
class Company extends Model
{
public function getEmployeeRepository(): EmployeeRepositoryContract
{
switch ($this->data_source_type) {
case 'azure':
// return new instance of AzureEmployeeRepository
case 'database':
// return new instance of DatabaseEmployeeRepository
default:
throw new InvalidArgumentException(
sprintf('Unsupported data source type: %s', $company->data_source_type)
);
}
}
}
And then call methods on it in your controllers, etc:
$allEmployees = $company->getEmployeeRepository()->all();