Peeps, I'm lost. Tried everything and after 5 hours of searching through the 10th page of Google hits, I give up. Maybe I just dont know how to ask Google the correct keywords..
I have this scenario: In lumen app, lets call it X, I have require custom packages CRUD and Storage, Storage is using functionality of CRUD.
StorageService has:
use Crud\Services\BaseService;
class StorageService extends BaseService{}
And Crud\BaseService has constructor, that uses Model:
use Illuminate\Database\Eloquent\Model;
class BaseService
{
protected $model;
public function __construct(Model $model)
{
$this->model = $model;
}
}
When I try to do anything with my app X, I get error:
Target [Illuminate\Database\Eloquent\Model] is not instantiable while building [Lumee\Storage\Services\StorageService]
I cannot get my head around how to get to proper class of Model, since I saw, that Model is abstract class.
Also, I'm using this CRUD package successfully in another App, only difference is, there CRUD is used directly in app, not via some other package. I'm confused, why there is working without any additional bindings and service registering..
EDIT: Added some binding into StorageServiceProvider (boot and register methods):
$this->app->bind(BaseService::class, function(){
return new BaseService(new Model());
});
And registered StorageServiceProvider in my boostrap/app.php:
$app->register(Storage\Providers\StorageServiceProvider::class);
Thing still returns same error. I tried with binding in CrudServiceProvider, nope.
you can't get object from abstract class (Model class) to solve this try this :
use Illuminate\Database\Eloquent\Model;
class BaseService
{
protected $model;
}
suppose your model is (Storage) :
use Crud\Services\BaseService;
class StorageService extends BaseService{
public function __construct(Storage $model)
{
$this->model = $model;
}
}
I'm trying to figure out how to inject a dependency into a class in Laravel.
My structure:
SimpleController extends BaseController
{
public function example(SimpleModel $model, SimpleValidationRequest $request)
{
$result = $model->doStuff()
return $this->makeResponse($result);
}
}
SimpleModel extends Model
{
public function doStuff(ComplexService $service)
{
$service->doComplexLogic($this);
}
}
I have registered the ComplexService in my own service provider:
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(ComplexService::class);
}
}
I want to inject the service straight into the simpleModel's doStuff method, without having to inject it into the controller and then into the model. We're busy moving a monolithic application to Laravel and have service classes that contain all the complex business logic. Much of the logic is shared between different classes, so a controller method might call a model that calls a service that ends up making 4 or 5 calls to other services, and I want to be able to inject another service into any method that needs it without having to send it down from the controller all the way through to the bottom method that might need it.
Is there a way to do this? I have been looking online but everything I've found has required me to inject the service into the controller and then sending it through the application from there, which I want to avoid.
You can simply call the singleton inside the method via the app() helper
SimpleModel extends Model
{
public function doStuff(ComplexService $service)
{
app()->singleton(ComplexService::class)->doComplexLogic($this);
}
}
or recover the singleton by injecting it in the model via it's __construct() method.
I have a project on Laravel and need to do refactoring. I've read about Service provider and Dependency injection and have some questions.
This is a short structure: user model, event model, favorite user model and etc. Also, there are controllers for all models. Every event has a creator and client (user relationship). In every class, I am injecting appropriate service: User Service, Event service, Favorite user service and etc.
Let's consider the example - I want to delete the user:
class UserController extends Controller
{
/**
* #var UserService $userService
*/
protected $userService;
/**
* UserController constructor.
* #param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
protected function delete(int $id)
{
$user = User::find($id);
if ($user) {
$this->userService->setUser($user);
$this->userService->delete();
}
}
Inside User service, I am processing user deleting - update the appropriate field. Also, I need to cancel all user events and delete favorite users.
My question is where should I do it? Should I inject event and favorite user service in UserController or in UserService? Or maybe there is a better way to do this action. Thx in advance
Seems like you have many actions depending on deleting user, so I would consider using Events and inside each listener handle the specifics of it.
class UserController extends Controller
{
/**
* #var UserService $userService
*/
protected $userService;
/**
* UserController constructor.
* #param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
protected function delete(int $id)
{
if(!$this->userService->delete($id)) {
// return some error;
}
event(new UserWasRemoved($id));
// return success response
}
class DeleteUserService {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function delete($id){
return $this->user->delete($id);
}
}
// app/Providers/EventServiceProvider
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
UserWasRemoved::class => [
CancelUserEvents::class,
RemoveUserFavorites::class,
// etc...
],
];
}
if deleting a user is much code, I will create DeleteUserService class which will contain all the code needed to delete a user and the effects of the delete.
class DeleteUserService {
public function __construct(int $userId)
{
$this->userId = $userId;
}
public function delete(){
$this->deleteUser();
$this->updateAppropriateFields(); // of course the name should be clearer
$this->deleteEvents();
$this->deleteFavoriteUser();
...
}
private function deleteUser(){...}
private function updateAppropriateFields(){...}
private function deleteEvents(){...}
private function deleteFavoriteUser(){...}
...
}
and in your controller either you inject the service or instantiate a new instance in the controller method
class UserController extends Controller
{
...
public function delete(int $id)
{
$user = User::findOrFail($id);
$deleteService = new DeleteUserService($user->id);
$deleteService->delete();
}
}
it's always a good idea to break your large function into one or more classes.
I suggest you abandon your approach to using services like this. Everything that you implement with services has already been implemented in Laravel, only even easier. You are now implementing more cumbersome logic on top of a simple, ready-made one.
For each object of your subject area (user, event, favorite user) add model class. Add in them the information of tables, the data from which belong to them - unless of course you use relational storage Eloquent Model Conventions. Here I have a question for you - does the favorite user entity need a separate class? If the User and the FavoriteUser have the same characteristics (that is, class members in the implementation), then there is no need to distribute them into different classes, and it is enough to add an additional isFavourite() (bool) attribute - in the class and in the table.
Implement the necessary methods in the controllers for each of your model classes as described in the documentation Defining Controllers. Depending on the type of the client part, the return of the response can be either JSON for the RESTful API, or a blade template with the transmitted data Views. Here, in the controller, you should implement a method to delete the model.
If you do not want the logic to be similar, that is, get rid of the similar methods all(), get(), post(), put(), delete() and others for UserController, for EventController, ... (with the exception of model classes - which will be different), then I advise you use the following architectural trick (this is optional, of course). Develop a universal layer - a class of a universal model, a class of a universal controller, a class of a universal model repository (if you use it in development). And in the controller, describe the common logic for all model classes, all(), get(), post(), put(), delete(). And then inherit each concrete class of the model from the universal, each concrete class of the controller from the universal - and so on. But!
In a concrete class of the model, it is necessary, for example, in an array, to list the attributes of the relational storage table, where you get the data from; it is also necessary to specify the name of the class in the variable - so that the controller can understand which class it should work with.
And in the controller in any way pass data about the model class - for example, using DependencyInjection Dependency Injection & Controllers.
With this approach, the classes of concrete controllers become thin, and the increase in code in them occurs only due to the redefinition of universal methods or the implementation of custom ones.
The advantage of this approach is also that there is no need to add routes of a similar structure. For example, a universal route will suffice for you
Route::get('{entity}/{id}', function ($entity, $id) {
$module = ucfirst($entity);
Route::get("{$entity}/{$id}", "{$module}Controller#get");
});
instead of many of the same type
Route::get('user/{id}', 'UserController#get');
Route::get('event/{id}', 'EventController#get');
and the like.
I have gone through the Laravel documentation and found that every request follows the Middle layer -> Controller layer -> Resource Layer flow.
But for my project I have a huge business processing logic which needs to be written. So, I am looking for a service layer option where execution control will be passed from Controller and then service layer will do the processing logic along with database fetch. But I didn't find anything linked with service layer part in artisan.
So, can you suggest me how can I implement a service layer in my project?
What about creating a Services folder under app/, and use Controllers dependency injections?
It would be something like this:
MyService.php
<?php
namespace App\Services;
use App\Models\Bar;
class MyService
{
public function foo(Bar $bar)
{
// do things
}
}
MyController.php
<?php
namespace App\Http\Controllers;
use App\Services\MyService;
use App\Models\Bar;
class MyController extends Controller
{
protected $myService;
public function __construct(MyService $myService)
{
$this->myService = $myService;
}
public function handleRequest(Bar $bar)
{
$this->myService->foo($bar);
}
}
To maintain my Laravel application and save myself from a lot of duplicate code I have made the following solution:
BaseController
class BaseController extends Controller
{
public function get($id){
return $this->baseService->get($id);
}
public function getAll(){
return $this->baseService->getAll();
}
}
BaseService
class BaseService
{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function get($id){
return response()->json($this->model->where('id', $id)->first());
}
public function getAll()
{
return $this->model->get();
}
}
MyController
class MyController extends BaseController
{
protected $model;
protected $baseService;
public function __construct(){
$this->model= new Model();
$this->baseService = new BaseService($this->model);
}
/**
* This controller has all the functionality from BaseController now
*/
}
What I'm wondering if this is a good method. Should I stick with this or should I use a different approach? I've heard about Traits but not sure if they are doing the same thing. It's Laravel 5.5 I'm using.
Yes, traits are used to move methods out of a controller regularly. A good example that the Laravel framework uses is the ThrottlesLogin trait. Take a look at https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Auth/ThrottlesLogins.php#L20
to see how the methods are moved outside of a controller but can be still accessed by importing the trait using the use keyword.
While traits would work for your use case I wouldn't use them here for the functionality you are looking for. I would use the repository pattern. It would better separate your code and make it more reusable.
Take a look at https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more information on the repository pattern. Basically, you would separate your code into a separate repository and use Laravel's built in IoC to inject the repository into your controller.
MyController
class MyController extends Controller
{
protected $repo;
public function __construct(MyRepository $myRepository)
{
$this->repo = $myRepository;
}
public function index()
{
$myStuff = $this->repo->all();
}
// you can also inject the repository directly in the controller
// actions.
// look at https://laravel.com/docs/5.5/controllers#dependency-injection-and-controllers
public function other(MyRepository $repo)
{
$myStuff = $repo->all();
}
}
This is the perfect use case for a Trait. Traits are intended for reusable functions. They're super simple to implement, and won't take more than a few minutes to change what you have.
Here is a great article on them: https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5