I'm building an app with Laravel 5.1 using my own service providers to separate some business logic, but I can't seem to find a way to acces other methods of the service provider from within itself.
Using the function name tries to look for something in the namespace App\Providers and there's no $this because it's singleton pattern, so how can I do it? Does it have to "use" itself?
I also don't want an external helper as this function would be specific to this service.
Simply enough it can be done using self::method() or static::method() but your method has to be declared as static.
Related
There are many questions regarding loading custom helper classes in Laravel. However, none of them focus on the loading them with proper initialization.
As of Laravel version 5.3 we can use psr-4 autoloading which is autoloading the entire app/ directory. However, classes are loading but never initialized.
I have my helper class inside the app/helpers/support.php. This class has a constructor, where I want to load some important configuration in order to make the helper usable.
So how can I load my helper but ALSO initialize it properly in Laravel? Right now I am simply working-around the problem by using new \App\Helper\Support(); inside AppServiceProvider.php.
Edit: I'm using the following approach to maintain my helper class:
Best practices for custom helpers on Laravel 5
It seems like what you have is a service. Rather than creating an instance, you can declare it in your app service provider and inject it as a dependency when you need it.
In your register method:
$this->app->bind(\App\Helper\Support::class);
You can now use dependency injection to get an instance of your class. You can also make an instance like this:
app()->make(\App\Helper\Support::class);
If you only want one instance to exist at any given time, use singleton rather than bind.
I recommend reading the service container documentation:
https://laravel.com/docs/5.5/container
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.
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.
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.
I implemented a role/permission system. Now I want to add a method to Laravel router so I can make something like this:
Route::get('sales', 'SaleController#index')->allow('Salesman');
I know that I can use #can('Salesman') (View) and $user->can('Salesman') (Controller) but I found so much readable the way I'm trying to do it since I'll be able to see all role permission access in the routes file.
You can override the router class, then register it into service container to be used by Route facade.
To be more clear:
Write a class that extends Laravel's router (I think Router class). To find this, open the Route facade, then find its service provider. From there, it should be easy to find the router class.
Write a class that overwrites that router. Make sure to extend the class you found before.
Write a service provider that overwrites the router services. The practically means to register your service under the same key name you find in Route facade.
And that should be it. Your service is now picked by Route facade automatically.
As you're using the facade to generate the routes. This should be quite easy. The facade can be overruled in the config/app.php facades array.
You can generate your own Facade class and replace the native one with yours. Which in fact is a Router class. In order to implement the functionality you need to extend and override the following in sequence:
Facade
Router::newRoute
Route
By extending the last one and returning those in the newRoute method of the Router, you'll be able to overrule the logic of Laravel.
I like to spend time studying how frameworks are coded in attempt to better my code.
As far as I know the Scope Resolution Operator in PHP calls a function in a class as a static function, meaning that you do not have access to '$this' because the class hasn't been instantiated.
But when I started reading up how the Laravel 4 Auth works I noticed that the documentation tells you to use Auth::check() or Auth::user() to retrieve information, yet the code in those functions is using many '$this' statements.
Can anyone explain to me how they are able to retrieve the instance properties if the functions are being called as static methods?
Here is the link to the github raw file for Laravel Auth
https://raw.githubusercontent.com/illuminate/auth/master/Guard.php
Laravel uses a development pattern known as Facades and Inversion of Control (IoC) in order to take static calls to some objects (the 'Facade') and retrieve an actual instance of an object (from the IoC container) to call the method on.
Put another way, when you do Auth::check() and Auth::user() those seemingly static calls get replaced with actual object instances from within the IoC container, so Auth::check() becomes $auth->check() with $auth being derived from within the container.
This allows you to 1) Write Auth::check() instead of $auth = new Auth; $auth->check() and 2) let the IoC container do all of the dirty work around actually creating the instance you want, so if implementation details change later you don't have to rewrite any code that uses the Auth class.
See this documentation page about facades and this question about IoC in general for more information.
As a side note, the Auth facade referred to in Auth::check() et al is actually this class: https://github.com/laravel/framework/blob/master/src/Illuminate/Support/Facades/Auth.php
It's a Fcade.
When you're calling Auth::{anything}, you're actually calling Illuminate\Support\Facades\Auth. The static method is only used as an entry point.
This is a simplified version of the Facade design pattern:
http://sourcemaking.com/design_patterns/facade/php
I have multiple functions in my controller, and lots of them call $usermgr = $this->get('usermanager'); (where usermanager is a service defined in config.yml).
This means code is repeated multiple times. Is there a way to define $usermgr only once in the controller? Normally I'd consider a __construct but I believe thats not possible with a controller?
There is nothing wrong with getting the same service in multiple methods in a controller.
You can change your controller into a service ( http://symfony.com/doc/current/cookbook/controller/service.html and http://richardmiller.co.uk/2011/04/15/symfony2-controller-as-service/ ) and then inject that service. While that follows the best practises, your current way is not wrong.
You cannot request that service in the constructor, using the Symfony base Controller class, as the service container is set after initialization.