Another way to explain this is that I am trying to almost exactly mimic what the built in Registrar service does in Laravel 5 where it registers a new user. But I want a different "Registrar" service for each report type based on a selection from the user. I don't know how to call the different implementations based on user input, and I for sure don't want to use a switch statement or a bunch of if statements.
Multiple services implementing same interface, switching at runtime
This is going to be hard for me to explain as I don't fully understand the concepts I'm discussing, so bear with me. I've also tried searching for an answer.
I'm trying to create multiple services that all implement the same interface/contract, and which service that is used depends on user input. What I have is multiple report types with different fields, and each type has it's own table with the custom fields. All of the reports share common fields, and those are in a reports table. I'm doing something like Class Table Inheritance, and I'm using polymorphism in Laravel to pull it off.
I have a contract in App\Contracts\Report.php that has a create() method defined. Then in App\Services I have a class for each report type that implements the contract with a create() method. Each version of the create method differs slightly based on the report type.
The part I'm lost on is how to use the different services based on user input. If I were to do what I would consider the wrong way, it would look something like this. In my controller, I would have a method like this:
public function create(ReportContract $report)
{
$report->create();
}
Then if I were to mimic a user selecting a Personal Injury report, I would do something like this:
$user_selection = "personal_injury";
$class = 'App\\Services\\' . studly_case($user_selection) . 'Report';
$this->create(new $class);
That would pass a new PersonalInjuryReport to the create method, and then that create method would create a new Personal Injury report using eloquent. That's not how I would really do it, it's just hard coded to see if it works, and it does. But it's wrong and I'm not sure how I'm supposed to go about making this work.
@i960 It looks good, you just need to bind the implementation at runtime, depending on some value - tell me how a user can choose.
@i960
In other words create a Service Provider that will bind the implementation based on the user selection - something like this:
protected $availableServices = ['SomeService', 'AnotherService', ...];
public function register()
{
$this->app->call([$this, 'registerMyService']);
}
protected function registerMyService(Request $request)
{
$selected = studly_case($request->get('user_selection'));
$service = (in_array($selected, $this->availableServices))
// if user selection is OK, then bind it
? $selected
// otherwise fallback to the default implementation
: 'DefaultService';
$this->app->bind('Your\Contract', "Some\Namespace\\{$service}");
}
Please or to participate in this conversation.