Laravel adding Gate with vendor:publish - laravel

So I am developing a composer package, that adds several of my reusable code to a fresh Laravel project. So far I've managed to add core translation files and some models, routes in my service provider with $this->publishes() and $this->loadRoutesFrom() in my boot() method.
Now I want to add Gates to that package, but I'm stuck. Somehow I should register these in the project's AuthServiceProvider on run. Would be very nice if anyone could give me some advice how to perform this task.

If you want to register policies, there is no need to use the AuthServiceProvider, you can simply use Illuminate\Support\Facades\Gate::policy($key, $value).
You can do that in your own ServiceProvider of your package. If you want to define abilities, you can add a boot method like this:
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
// ...
public function boot(GateContract $gate)
{
$gate->define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
}
This will resolve the gate instance for you and allow you to define abilities. It's important to use the boot method, since this way you can be sure every service is already registered.

Related

Managing Multiple API versions in Laravel

I'm working on exposing an API using one base URL (e.g. https://api.domain.com) and having that URL handle all versions of the API (the API consumer will need to send Accept-Version in the request header to indicate which version of the API they're trying to use).
How would I manage this approach in Laravel?
I was thinking that I could put all of my controllers, helpers, models, routes, config, etc. in a, say, 1.0.0 folder and use those for version 1 of my API. When I release a new version, maybe I make copies of the original code, put them in a 1.1.0 folder, and make changes there.
If I were to use this folder approach, what would I need to do in the routes to indicate which folder to use? How would my controllers know what models, helpers, config, etc. to use? Feels like this approach could get very messy and convoluted.
In your RouteServiceProvider.php you can define the routes for the application. Here you can also define the namespace, name prefix, and middleware for the routes. Simply add a new route map for each version of your api. Have the middleware check the version, redirecting if necessary, and set the name prefix/namespace to the correct version directory.
the RouteServiceProvider would look something like:
protected function mapApi-1-0-0-Routes()
{
Route::middleware(['api', 'version'])
->name('1.0.0.')
->namespace('1.0.0')
->group(base_path('routes/api.php'));
}
then your middleware would look something like
public function handle($request, Closure $next)
{
switch ($request->version) {
case "1.0.0":
$route = $request->version.$request->route()->getName();
break;
// more versions
return redirect()->route($route)->with($request);
}
I haven't tested this.
Route group name prefixes:
https://laravel.com/docs/7.x/routing#route-group-name-prefixes
Route namespaces:
https://laravel.com/docs/7.x/routing#route-group-namespaces
Redirecting named routes:
https://laravel.com/docs/7.x/redirects#redirecting-named-routes
Global middleware:
https://laravel.com/docs/7.x/middleware#global-middleware
Writing service providers:
https://laravel.com/docs/7.x/providers#writing-service-providers

Adding a route in Laravel as the last route, from a composer module?

I am making a module for Laravel, and for the ease of reusability, I am making it as a separate composer module.
In this module, I have to define a catch-all route, but I dont want it to override any of the manualy added routes, in the project.
Does anyone have a good idea how I can get this behaviour?
I am registering my route in the ServiceProviders boot() method like this:
public function boot()
{
$this->loadMigrationsFrom(__DIR__.'/migrations');
$this->loadRoutesFrom(__DIR__.'/routes/routes.php');
}
and the routes.php is also rather simple:
$regex = ".*";
Route::namespace('Asator\\Runepost\\Controllers')
->middleware(['web', DynamicContent::class])
->group(function($route) use ($regex) {
$route->any('{any}', 'RunepostFrontController')->where('any', $regex);
});
Is it possible to somehow add the route as the last route, after the manually added routes has run?
Just add your module's ServiceProvider after the App's RouteServiceProvider in config/app.php and make sure your catch-all-route is the last route of your module's routes.

Custom Variable in AppServiceProvider Laravel 5.5?

I want use a variable from my database to set a folder for custom views.
"class AppServiceProvider extends ServiceProvider"
$ActiveProject = ThemeConfig::where('module_type',"project")->where('active',"1")->first()->file;
After this, I get an active project name (like Nshop), and I want to set it in:
public function register()
{
$this->app['view']->addNamespace('Projects', base_path() . '/Projects/'.$ActiveProject.'/Views');
}
But I get an error.
How can I accomplish this task?
Using ORM Models in the AppServiceProvider doesn't work. This file is part of the boot process of Laravel where your models are not loaded yet. But you can rely on functions that are part of the Laravel core concept.
$ActiveProject = ThemeConfig::where('module_type',"project")->where('active',"1")->first()->file;
Becomes
$ActiveProject = \DB::table('theme_configs')->where('module_type',"project")->where('active',"1")->first()->file;

A way to clean up laravel

By default laravel is huge.
Its a way to clean up only needed depencies?
For sample, when i'm installing laravel, some default configs are provided. I dont need the API Routes or other, when i'm using the normal web-routes.
If you want to don't want to load API route you can simply comment out this line in RouteServiceProvider
public function map()
{
$this->mapApiRoutes(); //comment this line
$this->mapWebRoutes();
//
}
Hope this helps.
To make Laravel leaner, another good approach is to have a look on your ServiceProviders, which are loaded in config/app.php. Just deactivate all ServiceProvider you don't need and test your application.
ServiceProviders can also be loaded from packages. So take also attention to loaded packages through your composer.json.

Laravel 5 - Is there a way to use built-in authentication but disable registration?

I am building an administrative back-end and thus need to hide public user registration. It appears that if you want to use the built-in Illuminate authentication you need to add
use AuthenticatesAndRegistersUsers to your controller definition. This trait is defined here.
It appears as if it is impossible to disable registration if you want to use the built-in auth handlers... can someone show me wrong?
I'm using Laravel 5.2+ and I found that if you remove the Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers and use just Illuminate\Foundation\Auth\AuthenticatesUsers does the trick too.
Though /register is still accessible and will throw a fatal error.
This page talks about overriding the auth controller. Its worth a read, at a basic level it seems you can add the following lines to app\Http\Controllers\Auth\AuthController.php :
public function getRegister() {
return redirect('/');
}
public function postRegister() {
return redirect('/');
}
So if a user accesses the registration url it will redirect them away to a place of your choosing.
You can have your own form of registration. The only thing Laravel does is make it easy to authenticate on a users table because they create the model, build the db schema for users and provide helper methods to authenticate on that model/table.
You don't have to have a view hitting the registration page... But if you want to use the built in auth you still need to use (or set) a Model and a driver for database connections.
You can just remove that view and/or controller method from the route that links to the registration view and create your own (or seed the database manually).
But, no, you cannot forgo using Eloquent, and the User model and expect to use built in auth. Built in authentication requires that you specify settings in /config/auth.php. You may specific a different model (other than User) and you may specify a different table, but you cannot forgo the configuration completely.
Laravel is very customizable though, so you can achieve what you are looking to do... plus why not use Eloquent, it's nice.
Based on #shoo's answer, working with Laravel 5.2
Add the following lines to app\Http\Controllers\Auth\AuthController.php :
public function showRegistrationForm() {
return redirect('/');
}
public function register() {
return redirect('/');
}

Resources