Service layer in laravel 5.7 - laravel

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);
}
}

Related

Target [Illuminate\Database\Eloquent\Model] is not instantiable while building

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;
}
}

Laravel Livewire error when I add a constructor to call a service class

I've got a piece of code I want to reuse. I've read this Laravel cleaner code article and this other Laravel Services Pattern article, where I have realized I can reuse code in several places of the application by using services classes.
In this case, I created a new MyService class, inside a new folder app/Services/MyService.
namespace App\Services;
class MyService
{
public function reuse_code($param){
return void;
}
}
The problem comes when I want to call the class through the constructor inside a Livewire class component, as follows:
<?php
namespace App\Http\Livewire;
use App\Services\MyService;
use Livewire\Component;
use Livewire\WithPagination;
class LivewireTable extends Component
{
use WithPagination;
private $myClassService;
public function __construct(MyService $myService)
{
$this->myClassService = $myService;
}
public function render()
{
$foo = $this->myClassService->reuse_code($param);
return view('my.view',compact('foo'));
}
}
The error displayed is the following:
Argument 1 passed to App\Http\Livewire\LivewireTable::__construct()
must be an instance of App\Services\MyService, string given
(However, If I use a trait, there are no problems. But I am afraid then my traits collide as previous experiences)
How do I fix it? What am I missing?
Livewire's boot method Runs on every request, immediately after the component is instantiated, but before any other lifecycle methods are called
Here's the solution worked for me.
Solved
Just like #IGP said, reading in the livewire docs it says:
In Livewire components, you use mount() instead of a class constructor
__construct() like you may be used to.
So, my working code is as follows:
<?php
namespace App\Http\Livewire;
use App\Services\MyService;
use Livewire\Component;
use Livewire\WithPagination;
class LivewireTable extends Component
{
use WithPagination;
private $myClassService;
public function mount(MyService $myService)
{
$this->myClassService = $myService;
}
public function render()
{
$foo = $this->myClassService->reuse_code($param);
return view('my.view',compact('foo'));
}
}

Laravel dependency injection without relying on the controller

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.

Issue in creating REST Service using laravel

We are trying to develop an Android app that required a REST API to show data from web server.
We tried to use Laravel resource to create REST service like below:
Route::resource('list', 'ListController');
namespace App\Http\Controllers;
use mymodel
class ListController extends Controller
{
public function getShow($id)
{
$Jsondata=list($id);
return $JsonData;
}
}
But it's not working as expected need some token key or some other authentication and authorization need to know how to set.
We should utilize the Repository / Gateway design pattern:
For example, when dealing with the User model, first create a User Repository. The only responsibility of the user repository is to communicate with the database (performing CRUD operations). This User Repository extends a common base repository and implements an interface containing all methods we require:
class EloquentUserRepository extends BaseRepository implements UserRepository
{
public function __construct(User $user) {
$this->user = $user;
}
public function all() {
return $this->user->all();
}
public function get($id){}
public function create(array $data){}
public function update(array $data){}
public function delete($id){}
// Any other methods we need go here (getRecent, deleteWhere, etc) }
Then, create a service provider, which binds your user repository interface to your eloquent user repository. Whenever you require the user repository (by resolving it through the IoC container or injecting the dependency in the constructor), Laravel automatically gives you an instance of the Eloquent user repository you just created. This is so that, if you change ORMs to something other than eloquent, you can simply change this service provider and no other changes to your codebase are required:
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind(
'lib\Repositories\UserRepository', // Assuming you used these
'lib\Repositories\EloquentUserRepository' // namespaces
);
}}
Next, create a User Gateway, who's purpose is to talk to any number of repositories and perform any business logic of your application:
use lib\Repositories\UserRepository;
class UserGateway {
protected $userRepository;
public function __construct(UserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function createUser(array $input)
{
// perform any sort of validation first
return $this->userRepository->create($input);
}}
Finally, create our User web controller. This controller talks to our User Gateway:
class UserController extends BaseController
{
public function __construct(UserGatway $userGateway)
{
$this->userGateway = $userGateway;
}
public function create()
{
$user = $this->userGateway->createUser(Input::all());
}}
By structuring the design of your application in this way, you get several benefits: you achieve a very clear separation of concerns, since your application will be adhering to the Single Responsibility Principle (by separating your business logic from your database logic) . This enables you to perform unit and integration testing in a much easier manner, makes your controllers as slim as possible, as well as allowing you to easily swap out Eloquent for any other database if you desire in the future.
For example, if changing from Eloquent to Mongo, the only things you need to change are the service provider binding as well as creating a MongoUserRepository which implements the UserRepository interface. This is because the repository is the only thing talking to your database - it has no knowledge of anything else. Therefore, the new MongoUserRepository might look something like:
class MongoUserRepository extends BaseRepository implements UserRepository
{
public function __construct(MongoUser $user) {
$this->user = $user;
}
public function all() {
// Retrieve all users from the mongo db
}}
And the service provider will now bind the UserRepository interface to the new MongoUserRepository:
$this->app->bind(
'lib\Repositories\UserRepository',
'lib\Repositories\MongoUserRepository'
);
Throughout all your gateways you have been referencing the UserRepository, so by making this change you're essentially telling Laravel to use the new MongoUserRepository instead of the older Eloquent one. No other changes are required.
Number one is that what is not working? if you mean that the response is not showing then its because your function actually doesn't even seem to be going any where, and number two are you new to Laravel?
Okay if this is what you have:
namespace App\Http\Controllers;
use mymodel;
class ListController extends Controller
{
public function getShow($id)
{
$Jsondata=list($id); return $JsonData;
}
}
Then I can be safe to say a lot of things is wrong.
To my understanding using Route::resource('list', 'ListController'); in your routes file creates show, edit, update and destroy paths, and also expects to see these functions too (I have not proven this to the core though) but thats my understanding.
so you can simply start laravel life by doing having your routes with
Route::get('list', 'ListController#show')
Then change your ListController to something like this:
namespace App\Http\Controllers;
use mymodel;
class ListController extends Controller
{
public function show($id)
{
$jsonData= ['my' => 'json data'];
return $jsonData;
}
}
If this works for you, then cool else so many thing might already be wrong with your setup.
Note: you might need to take your time to learn to use laravel from the documentation page. If API is your interest then try DIngo api. Also try to learn to use markup :)
Hope this helps :)

Dependency Injection in Laravel 5 Package To Use or Not To Use

I am developing a package for Laravel 5, I decided to benefit from dependency injection in my package when using the Core classes of Laravel, but after reading more and also having asked this question
Best approach for Dependency Injection in Laravel 5 package
Now I came up with the idea that if we are using Facades so much and calling static methods like FaceadeName:nameOfMethod the Container actually creates an object for us and calls its method, so to some extend using dependency injection for laravel for classes which are also available through the Facades are is almost useless.
For example having this class:
class MyController extends \App\Http\Controllers\Controller
{
public $text;
public $lang;
public function __construct()
{
// Some codes here
}
public function myFunction(){
$this->text = \Lang::get('package::all.text1');
}
}
doing this:
App::bind('lang', function($app)
{
return new \Lang();
});
and then in the function:
public function myFunction()
{
$lang = \App::make('lang');
$this->text = $lang::get('package::all.text1');
}
is almost useless because we bind something to container that is already bound there
It is not a great idea to change the myFunction to
public function myFunction(\Lang $lang){
$this->text = $lang::get('package::all.text1');
}
as well, it might look like method injection but it doesn't bring so much advantages. Therefore it would be better not to use dependency injection for Facades in Laravel.
Please let me know if I am right or not and please argue my opinion with the right answer if I am wrong.
Facades provide a way of accessing the container through a class, so when you're accessing \Lang::function() you're actually calling app('translator')->function(). So in you're above example when you're binding the Lang facade into the container, you've then bound it twice, which isn't quite what you want.
All Laravel's functionality is already bound into the container and can be accessed by calling app('object'). You can see all the bindings here http://laravel.com/docs/5.0/facades
For dependency injection, you shouldn't be trying to inject the facades, but rather the classes the facades are already referencing. So for example, the \Lang facade references Illuminate\Translation\Translator which is bound to the container as translator
In your classes you can do the following
use App\Http\Controllers\Controller;
use Illuminate\Translation\Translator;
class MyController extends Controller
{
protected $translator;
// Dependency injection example
public function __construct(Translator $translator)
{
$this->translator = $translator;
}
public function index()
{
$text = $this->translator->get('package::all.text1');
}
// Method injection example
public function myFunction(Translator $translator)
{
$text = $translator->get('package::all.text1');
}
}

Resources