Lumen/Laravel - use custom router - laravel

Is there any out of the box solution without changing core to add custom router in to laravel or lumen. I already know that lumen is using different router from laravel, so I am wondering is there any possibility builded in core to change router?

I had the same question today. After some research I found a solution which will impact the core classes minimal.
Note: The following description is based on Lumen 6.2.
Before you start; think about a proper solution, using a middleware.
Because of the nature of this framework, there is no way to use a custom Router without extending core classes and modifying the bootstrap.
Follow these steps to your custom Router:
Hacky solution
1. Create your custom Router.
Hint: In this example App will be the root namespace of the Lumen project.
<?php
namespace App\Routing;
class Router extends \Laravel\Lumen\Routing\Router
{
public function __construct($app)
{
dd('This is my custom router!');
parent::__construct($app);
}
}
There is no Interface or similar, so you have to extend the existing Router. In this case, just a constructor containing a dd() to demonstrate, if the new Routerist going to be used.
2. Extend the Application
The regular Router will be initialized without any bindings or depentency injection in a method call inside of Application::__construct. Therefore you cannot overwirte the class binding for it. We have to modify this initialization proccess. Luckily Lumen is using a method just for the router initialization.
<?php
namespace App;
use App\Routing\Router;
class Application extends \Laravel\Lumen\Application
{
public function bootstrapRouter()
{
$this->router = new Router($this);
}
}
3. Tell Lumen to use our Application
The instance of Applicationis created relativley close at the top of our bootstrap/app.php.
Find the code block looking like
$app = new Laravel\Lumen\Application(
dirname(__DIR__)
);
and change it to
$app = new App\Application(
dirname(__DIR__)
);
Proper solution
The $router property of Application is a public property. You can simply assign an instance of your custom Router to it.
After the instantiation of Application in your bootstrap/app.php place a
$app->router = new \App\Routing\Router;
done.

Related

Class translator does not exist when using app()->setLocale() in app service provider

I'm trying to use localization in my Laravel 5.8 application. Following up with this How To Build An Efficient and SEO Friendly Multilingual Architecture For Your Laravel Application I have always do the same steps and have no problems. However, when I try it with Laravel 5.8 I keep getting Class translator does not exist from app()->setLocale(request()->segment(1)); I use that in the app service provider for some reason.
AppServiceProvider
<!-- language: php -->
public function register()
{
app()->setLocale(request()->segment(1));
Schema::defaultStringLength(191);
}
The register method is not to be used for using services.
Try adding your code in the boot method of the class.
Also I believe a better place for adding this is in a middleware then in the service provider.

Let a Package use the ServiceProvider of a "master"package in Laravel

I want to develop some packages for Laravel. So I want to create a "master" package fitting the Laravel-package-development guidelines as written on Laravel.com. Then I want to extend this package with other packages (or let other developers extend it).
Because of this, I want to make it as easy as possible for me/them. So I am looking for a way to register these sub-packages without the need of registering them in the config/app.php.
It would be great if these sub-packages could be registered and activated through the master-package, which is correctly registered via ServiceProvider, ClassAlias and Facade. Or is there a way to register them automatically in config/app.php?
I found a package on GitHub caffeinated/modules, which provides something like this, but there it's not possible to install and update new packages via composer.
It would be great, if one of you could help me with this problem, because I want to make it as easy as possible to extend the master-package.
Thanks!
You don't need caffeinated/modules, Laravel supports registering modules with all of their components out of the box, so this package is unnecessary.
What I usually do for my modules is - I have a main provider that registers the other providers of the other modules:
class MainModuleServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->register( FirstModuleServiceProvider::class );
$this->app->register( SecondModuleServiceProvider::class );
}
}
And in each of these providers I register providers for the module views, routes, etc.:
class FirstModuleServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->register( RouteServiceProvider::class );
$this->app->register( ViewServiceProvider::class );
}
}
In these providers I load the views, routes and publish the migrations as described in the Laravel doc.

How to integrate in Laravel 5 a Package from Packagist?

I'm working with laravel 5 and trying to integrate the following package:
exacttarget/fuel-sdk-php
I executed on my project:
composer require exacttarget/fuel-sdk-php
So I had on my vendor dir exacttarget provider.
First thing I've noticed this particular package doesn't use namespaces, so it still calls require directives but not "use \path\namespace"
Is it a right approach? I haven't seen many packages yet but among my past experience doesn't look to me the right approach to write a package...
After this I edit condif/app.php to use ET_Client class.
'providers' => [
...
'ET_Client',
...
],
Once I did this, I got an error: looks like Laravel frmwk tries to instantiate the class, that needs some parameters to work, even if I'm not yet using it (istantiating). It this a normal behavior from Laravel?
Am I missing something ?
The providers array is for registering service provider classes. Unless ET_Client extends Laravel’s base ServiceProvider class, it’s not going to work.
Instead, just add the use statements to your PHP classes as and when you need to use the class:
<?php
namespace App\Http\Controllers;
use ET_Client;
class SomeController extends Controller
{
public function someAction()
{
// Instantiate client class
$client = new ET_Client;
// Now do something with it...
}
}

Dynamic paths for laravel 5

While building multi-tenancy packages for Laravel 5 I had to find out how to make the paths and namespaces dynamic.
This would involve:
views; adding a template directory dynamically that is available in the root namespace
lang; adding a language directory dynamically that is available in the root namespace
routes; adding a routes file dynamically
config; merging additional configuration files from a dynamic location
vendor; allowing custom vendors and packages to be available from a dynamic location
views
Using a service provider you can use the following in your boot() method for views to be available in the root namespace (view('your-view') instead of view('package::your-view')):
$this->app['view']->addLocation('/your/new/location');
lang
Using a service provider you can use the following in your boot() method where $path is the new path for your root namespace translations:
$app->bindShared('translation.loader', function($app) use ($path)
{
return new \Illuminate\Translation\FileLoader($app['files'], $path);
});
$app->bindShared('translator', function($app)
{
$translator = new \Illuminate\Translation\Translator($app['translation.loader'], $app['config']['app.locale']);
$translator->setFallback($app['config']['app.fallback_locale']);
return $translator;
});
routes
Routes is by far the easiest. Simply include them using a require_once or by using the Laravel method: \File::requireOnce().
config
I used a directory that would allow a tenant to overrule core configs. Please advice there are no security nor sanity checks here so access should be limited.
Using a service provider you can use the following in your boot() method
foreach (\File::allFiles('/path/to/configs') as $path) {
$key = \File::name($path);
$app['config']->set($key, array_merge(require $path, $app['config']->get($key, [])));
}
This will merge existing configurations by overruling their values with the provided config files.
vendor
Really interesting is the possibility to use dynamically loaded classes. In order to do this you will need to use the ClassLoader addDirectories() method in your service provider
\Illuminate\Support\ClassLoader::addDirectories(['/path/to/vendors']);
additional considerations
The above code can be implemented using service providers. In order for a server provider to work you must add them to the config/app.php file under the providers array. Not doing so will not enable any of the code in the service provider.

Laravel 5 binding other object to contracts

I started using Laravel 5 and tried to learn things about contracts but i still have some questions about them.
For example I want to alter the Illuminate\Contracts\Auth\PasswordBroker contract (used in App\Http\Controllers\Auth\PasswordController )
The contract is an Interface but somehow Laravel knows what implementation belongs to that contract..
I want to change the implementation to my custom one.
But what is the correct way of loading my custom PasswordBroker class?
Should i bind my custom class in the AppServiceProvider?
$this->app->bind(
'Illuminate\Contracts\Auth\PasswordBroker',
'App\Services\MyPasswordBroker'
);
Where does Laravel itself bind the default implementations?
It's in 'Illuminate/Foundation/Application.php'
'auth.password' => ['Illuminate\Auth\Passwords\PasswordBroker', 'Illuminate\Contracts\Auth\PasswordBroker'],
Can I just overwrite the default bindings?
According to the official documentations: Yes.
You can easily extend and override this class within your own application by overriding this binding.
But remember to replace the original service provider in the config/app.php
Note that this class extends the HashServiceProvider, not the default ServiceProvider base class. Once you have extended the service provider, swap out the HashServiceProvider in your config/app.php configuration file with the name of your extended provider.
Your case
So, in your case, you need to extend the 'Illuminate\Auth\Passwords\PasswordResetServiceProvider' to remain other things happened in the service provider.
Take a look at the default service provider.
Let me know if you have other questions.

Resources