Reputation: 3051
I am developing my first API with Lumen. Normally I am using services for separating business logic or reused code from the controllers and share it with other controllers.
How to do this with lumen? Where to put the services? I only see ServiceProviders to register these services but for me it's not clear where and how to define them.
Upvotes: 8
Views: 2418
Reputation: 2076
Services as a Service class? Service classes are not part of a framework, it's more like an application architecture problem you are trying to solve here.
Depending on the project you are working on, either a Services folder in the app folder (if you go for the folders by type structure) or the feature folder it belongs to (if you go for app folders by feature style). These are just 2 of the many possible ways for folder structures.
It's different for every project so, it's up to you to decide where to put the service classes and how you are going to structure your app.
Remember to stick to one convention throughout the project development cycle. If you can't think of it right now, structure your classes later in the refactoring sessions. I usually get a lot more ideas when I am working on something else rather than at the start when I am thinking about it.
Upvotes: 6
Reputation: 9771
Lumen and its big brother Laravel come with a service container, which handles the dependencies injection.
To resolve things out of the container, you may either type-hint the dependency you need on a class that is already automatically resolved by the container, such as a route Closure, controller constructor, controller method, middleware, event listener, or queued job. Or, you may use the
app
function from anywhere in your application:
$instance = app(Something::class);
That's for "resolving things out". Registering the "things" is what the service providers are for. A service provider is just a class that extends Illuminate\Support\ServiceProvider
and binds interfaces or classes to concrete implementations. (Read the docs for a detail on how to write your own.)
Example: Create some test route:
$app->get('/test', 'TestController@test');
and create the controller method, type-hinting a parameter:
public function test(DatabaseManager $dbm)
{
dd($dbm);
}
You will see that the DatabaseManager interface is resolved to a concrete class, properly instantiated and configured with your DB config. That's because at some point the framework is calling a service provider which takes care of doing that.
Any custom providers you may want to include are set in /bootstrap/app.php
like so:
$app->register(App\Providers\AuthServiceProvider::class);
(Otherwise if you ask for a class that hasn't been bound by a provider, the framework just injects a new
instance of that class.)
So, for this problem you probably want some repository class where you can encapsulate all database access.
Example:
// app/Repositories/ProductRepository.php
private $db;
public function __construct(DatabaseManager $dbm)
{
$this->db = $dbm->connection();
}
public function findById($id)
{
return $this->db->table('products')->where('id', '=', $id)->get();
}
//routes.php
$app->get('products/{id}', 'ProductsController@show');
//ProductsController.php
public function show(ProductRepository $repo, $id)
{
$product = $repo->findById($id);
dd($product);
}
It's interesting in this example that you call for a ProductRepository injection, and, since it has a DatabaseManager dependency, the framework handles the instantiation of both.
I hope this begins to answer your question about managing business logic in service providers. I guess another typical use case is authorization handling. You can follow the docs on this subject after this intro.
Upvotes: 6