Laravel - forgetParameter - laravel

My project is multi language, so in most route I add parameter "locale". But latter I do not need to pass "locale" parameter to my controllers. I try to remove this parameter using forgetParameter() method but when I use this method then I have error "Route not bound".
So what I'm doing wrong.
How to remove "locale" from all routes?
Laravel 5.8
My route file.
Route::group(['prefix' => '{locale}','where' => ['locale' => '[a-zA-Z]{2}']], function() {
Auth::routes([app()->getLocale()]);
Route::get('/', 'HomeController#index')->name('mainPage');
Route::get('/user/{id}','UserController#showUser')->name('getUserProfile')->forgetParameter('locale');
Route::get('/user/{id}/edit','UserController#editUser')->name('editUserProfile')
->middleware('can:editUser,App\User,id')->forgetParameter('locale');
Route::patch('/user/{id}/edit','UserController#updateUser')->name('updateUserProfile')
->middleware('can:updateUser,App\User,id')->forgetParameter('locale');
});
It's not duplicate with this question - Laravel 5.4: How to DO NOT use route parameter in controller
Solution in that question doesn't work in my case. And my question is why "forgotParamter()" throw an error?
Other question is, why I can't use this construction in middleware:
$request->route()->forgetParameter('locale')
I have following error:
Call to a member function is() on null
Thank you.

Try to forget the parameter in an inline middleware in the controller's constructor. Actually, I would use a base controller: 1, get the route value; 2, set to a protected property, so inherited controllers can access to the value; 3, forget the parameter.
<?php
// Localized/Controller.php
namespace App\Http\Controllers\Localized;
use App\Http\Controllers\Controller as ControllerBase;
use Illuminate\Http\Request;
class Controller extends ControllerBase
{
protected string $currentLocale;
public function __construct()
{
$this->middleware(function ($request, $next) {
// If you need to access this later on inherited controllers
$this->currentLocale = $request->route('locale') ?? 'en';
// Other operations, like setting the locale or check if lang is available, etc
$request->route()->forgetParameter('locale');
return $next($request);
});
}
}
<?php
// Localized/UserController.php
namespace App\Http\Controllers\Localized;
use Illuminate\Http\Request;
// Extends the our base controller instead of App\Http\Controllers\Controller
class UserController extends Controller
{
public function show(Request $request)
{
// No need of string $locale arg
dd($this->currentLocale);
}
}

Related

Target class [PostController] does not exist. but it dose

The error I am getting is: Target class [PostController] does not exist but it does.
Route web.php
Route::get('/post', 'PostController#index');
Route::post('/post', 'PostController#store');
Route::get('/', function () {
return view('create');
});
PostController.php
namespace App\Http\Controllers;
use App\Post;
use Redirect,Response;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
return view('create');
}
public function store(Request $request)
{
$data = json_encode($request);
Post::create($data);
return back()->withSuccess('Data successfully store in json format');
}
}
This error comes in Laravel new version because there is no namespace prefix being applied to your route groups that your routes are loaded into. In the old version of Laravel, the RouteServiceProvider contained a $namespace property which would automatically be prefixed onto the controller route.
To solve this, you either can go to RouteServiceProvider and uncomment the line:
protected $namespace = 'App\\Http\\Controllers';
Or you can use closure-based syntax:
use App\Http\Controllers\PageController;
Route::get('/page', [PageController::class, 'index']);
Another way would be to use the fully qualified class names for your Controllers:
Route::get('/page', 'App\Http\Controllers\PageController#index');
use this line on the top of the (web.php) maybe your problem will resolve
use App\Http\Controllers\PostController;

Setting the route parameter in the middleware in Laravel

I am developing a Laravel application. I am doing route model binding in the middleware.
I have the routes like this
Route::group([ 'prefix' => 'department/{department}', 'middleware' => [ 'auth.department' ] ], function () {
Route::post('employee/create', 'EmployeeController#store')->name('employees.store');
});
This is my auth.department middleware (AuthDepartment)
class AuthDepartment
{
public function handle($request, Closure $next)
{
$department = Department::find($request->department);
//do something with the department
//I want to set the $department (Department model) in the place of {department} in the route.
return $next($request);
}
}
This is EmployeeController
class EmployeeController extends Controller {
public function store($department)
{
}
}
As you can see in the code, I am using $department parameter to get the department id from the route. But instead of getting the integer as the parameter, I want to bind the model like this.
class EmployeeController extends Controller {
public function store(Department $department)
{
}
}
With my current code, it is not working. I tried to set the route parameter in the middleware as follow to match (bind model) the value in the action.
$request->route()->setParameter('department', $department)
But it is just not working. How can I set/ replace the route parameter with a model in the middleware which can be binded to the parameter in the action of the controller? Is it possible? What could be the better approach?
If I used
$request->route()->setParameter('department', $department)
to set the parameter, I cannot set type in the action of the controller like this.
store(Department $department)
But this is fine
store(Department $department)
But I want this
store(Department $department)
Laravel already has this built in. It is called Route Model Binding.
https://laravel.com/docs/5.7/routing#route-model-binding
Remove the middleware and instead keep your controller as it is. Laravel will automatically use the ID in the request to find the model and give you an instance of it. If the model cannot be found, Laravel will throw a 404 response for you.

Laravel sharing data with all views

I'm trying to run a user-related query to fetch data to appear in the top bar of my site on every view.
I've created a new BaseController according to the first answer here:
How to pass data to all views in Laravel 5?
and that's working for a simple test (just sharing a typed-out variable), but when I try and use Auth::user()->id in the __construct method of BaseController (which in my other controllers always returns the ID of the currently logged in user), I get Trying to get property 'id' of non-object.
I've tried adding use App\User at the top of BaseController (even though it isn't usually needed) and also tried adding in the bits for Spatie laravel-permission plugin, but neither has any effect.
I tried dd on Auth::user() and just get 'null'. My feeling is that the user details maybe haven't been loaded at this stage, but BaseController extends Controller same as MyWorkingController extends Controller so I'm not sure why Auth::user()->id doesn't work here when it does normally?
Create a Base Controller which has all the information that you want to share too all controllers/pages/views and let your others controllers extend it.
open file AppServiceProvider.php from folder Providers and write below code in boot function
view()->composer('*', function ($view)
{
$view->with('cartItem', $cart );
});
And now go to your view page and write :
{{ $cartItem }}
You cannot access Auth in constructors because middleware has not been run yet. You can use either View composer or give try this way though i haven't tested.
class BaseController extends Controller {
protected $userId;
public function __construct() {
$this->middleware(function ($request, $next) {
$this->userId= Auth::user()->id;
return $next($request);
});
}
}
Write this in AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
use DB;
use Auth;
use App\Cart;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Schema::defaultStringLength(191);
view()->composer('*', function ($view)
{
view()->composer('*', function($view)
{
if (Auth::check()) {
$cart = Cart::where('user_id', Auth::user()->user_id)->count();
$view->with('cartItem', $cart );
}else {
$view->with('cartItem', 0);
}
});
});
}
}
In you view simply write
{{ $cartItem }}
For anyone interested, I just encountered the same problem and I've solved it with ServiceProvider:
Define your custom ServiceProvider with the command
php artisan make:provider CustomServiceProvider
Add a reference to your service provider in the config\app.php file, specifically in the providers array, adding this item to it:
\App\Providers\CustomServiceProvider::class,
Declare the variables you want to share in your provider's boot() method and share them by using the view()->share method:
public function boot()
{
$shared_variable = "Hello";
view()->share('shared_variable', $shared_variable);
}
You can now reference your variable in your blade files with the standard notation:
{{ $shared_variable }}

access auth for boot method to use variable in master blade

When I am trying to access Auth::user()->id;. its give me
Trying to get property 'id' of non-object
i am trying to access it in boot method for App\Providers
namespace App\Providers;
class AppServiceProvider extends ServiceProvider {
public function boot()
{
Schema::defaultStringLength(191);
$value = Auth::user()->id;
view()->composer('layouts.member', function ($view) use ($value) {
$view->with('value', $value);
});
}
}
I am going to make builder-bulder for query to use variable into master layouts blade.
You can't use Auth facade in the AppServiceProvider as the application is not fully booted yet.
Also, you will get the same error if there is no authenticated user. So it's better to wrap it in an optional method to avoid this error. In this case the value will be null.
However, you can use it inside the closure if you want that's what you want.
public function boot()
{
Schema::defaultStringLength(191);
view()->composer('layouts.member', function ($view) {
$value = optional(Auth::user())->id;
$view->with('value', $value);
});
}

How to grab URL path after locale "us_en" in Laravel 5.4?

Im am new in Laravel and Im tryig to grab in the route, everything that comes after locale ("us_en/").
This my controler
<?php
namespace App\Http\Controllers\SitePublic;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\App;
class HomeController extends Controller
{
public function index(Request $request,$account,$location) {
dd($request->path());
$loc=explode("_", $location);
$locale = $loc[0];
$lang= $loc[1];
App::setLocale($lang);
return view('homeProfPublic')->with(['account' => $account,'active' => 'home','lang'=>$lang,"locale"=>$locale]);
}
}
For now I am using $request->path() to grab everything in the route.
My Route map is like this
mySite.com/userAccount =>User's home page with English as default language
mySite.com/userAccount/us_sp =>User's home page in Spanish
mySite.com/userAccount/us_sp/contact =>User's contac page in Spanish
...
So the $request->path() could give me the full URL and I could use php explode to grab all after locale (if it is the case).
So my question is if is there some function or method already done in Laravel to solve this situation? If yes what is it?
You don't need to use $request
If you set the route properly: you can receive the parameters in your controller function
You can set either 3 routes to separate the logic in different functions or one with optional parameters
Route::get('/userAccount/{language?}/{method?}', 'YourController#index');
And then, in your controller specify default values for the parameters:
public function index($language=null, $method=null) {
list($locale, $lang) = explode('_', $language);
var_dump($locale);
var_dump($lang);
var_dump($method);
}
And your will get for the url /userAccount/us_sp/contact
string 'us' (length=2)
string 'sp' (length=2)
string 'contact' (length=7)
UPDATE You can create a middleware and process all the urls from there
php artisan make:middleware ProcessLanguageRoutes
You need to register the middleware in the app/Http/Kernel.php file
protected $middlewareGroups = [
'web' => [
...
\App\Http\Middleware\ProcessLanguageMenu::class,
],
And then, you can process the data in the handle function checking the $request variable
public function handle($request, Closure $next)
{
if ($request) { // check something
// do something
}
return $next($request);
}

Resources