i'm trying to get selected language in my construct to use in any function in that class:
my route:
Route::group(['prefix' => 'admin', 'middleware' => ['AdminMiddleWare','auth','localization']], function(){
Route::get('/', 'AdminController#index')->name('admin.index');
});
My Middleware:
public function handle($request, Closure $next)
{
if (Session::has('locale') AND array_key_exists(Session::get('locale'), Config::get('languages'))) {
App::setLocale(Session::get('locale'));
}
else {
App::setLocale(Config::get('app.locale'));
}
return $next($request);
}
My controller :
public $lang;
public function __construct()
{
$this->lang = Language::where('lang','=',app()->getLocale())->first();
}
public function index()
{
$lang = $this->lang;
return $lang;
}
but i'm getting only the default locale;
but if i change the controller to this:
public function index()
{
$lang = Language::where('lang','=',app()->getLocale())->first();
return $lang;
}
it will work...
how to get in construct and use it in all functions??
In Laravel, a controller is instantiated before middleware has run. Your controller's constructor is making the query before the middleware has had a chance to check and store the locale value.
There are multiple ways you can set up to work around this - the important thing is to make the call after middleware runs. One way is to use a getter method on your controller:
class Controller
{
/**
* #var Language
*/
private $lang;
public function index()
{
$lang = $this->getLang();
// ...
}
private function getLang()
{
if ($this->lang) {
return $this->lang;
}
return $this->lang = Language::where('lang','=',app()->getLocale())->first();
}
}
Related
Route:
Route::controller(PublicController::class)->group(function () {
Route::get('/index', 'index')->name('public.index');
});
View:
index.blade.php
wrong_browser.blade.php
In controller, this way is ok:
class PublicController extends Controller
{
public function index(Request $request)
{
if(is_wrong_browser)
return view(public.wrong_browser);
return view('public.index');
}
}
But how can I return view from another function, like this, without making a new route:
class PublicController extends Controller
{
public function index(Request $request)
{
$this->CheckBrowser();
return view('public.index');
}
public function CheckBrowser()
{
if(is_wrong_browser)
return view(public.wrong_browser);
}
}
You can use the method redirect.
return redirect()->route('index');
You could use middleware which you either define globally, or on specific routes.
class CheckUserActive
{
public function handle($request, Closure $next)
{
// determine value of $is_wrong_browser
$is_wrong_browser = true;
if ($is_wrong_browser) {
return redirect()->route('is-wrong-browser-route');
}
return $next($request);
}
}
It is bad practice to return a view from middleware instead redirect your user to another route.
Alternatively, you could have a base Controller that your Controllers extend which has the checkBrowser function defined on it and the extending Controllers therefore have access to:
class WrongBrowserController extends \App\Http\Controllers\Controller
{
public function checkBrowser()
{
// determine value of $is_wrong_browser
$is_wrong_browser = true;
if ($is_wrong_browser)
{
return view('wrong-browser-view');
}
}
}
class PublicController extends WrongBrowserController
{
public function index(Request $request)
{
$this->checkBrowser();
return view('index');
}
}
I've been using backpack in Laravel but I want to replace action-domain-responder architecture with MVC.So I've created an Action which my route refers like below:
Route::get('post',[
'as' => 'post.index',
'uses' => 'Core\Post\Actions\ApiGetListOfPostsAction',
'operation' => 'list'
]);
class ApiGetListOfPostsAction extends BaseAction implements IAction
{
private $service;
public function __construct(ApiGetListOfPostsService $service)
{
$this->service = $service;
}
public function __invoke(Request $request): mixed
{
$data = $this->service->process();
return response()->json($data);
}
}
and my service has this code:
class ApiGetListOfPostsService extends CrudController
{
use ListOperation, CreateOperation, DeleteOperation, UpdateOperation;
public function setup()
{
CRUD::setModel(\App\Models\Post::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/post');
CRUD::setEntityNameStrings('post', 'posts');
}
protected function setupListOperation()
{
CRUD::column('title');
CRUD::column('content');
}
public function process()
{
return $this->index();
}
}
I've extended CrudController in my service class but I've got this error:
Call to a member function hasAccessOrFail() on null
which related to the ListOperation Trait and this code:
public function index()
{
$this->crud->hasAccessOrFail('list');
}
I need to send all requests to the Service class. How can I pass requests to the service class?
When I deleted middleware from CrudController I have no problem.
$this->middleware(function ($request, $next) {
$this->crud = app()->make('crud');
$this->crud->setRequest($request);
$this->setupDefaults();
$this->setup();
$this->setupConfigurationForCurrentOperation();
return $next($request);
});
I think your Action is missing something.
When using inheritance from a parent class, it might help to put this line in your constructor.
public function __construct(ApiGetListOfPostsService $service)
{
parent::__construct(); // <- Subclass constructor
$this->service = $service;
}
Doc: https://www.php.net/manual/en/language.oop5.decon.php
The User model has an isAdmin() function to check if the user is an administrator. What to do next?
The best way is to use default laravel LoginController located under App\Http\Controllers\Auth\LoginController.
In that controller you can override authenticated method that is injected from AuthenticatesUsers trait, by simply adding that method in LoginController:
* #param Request $request
* #param $user
*/
protected function authenticated(Request $request, $user)
{
if ($user->isAdmin()) {
return redirect(route('admin-dashboard'));
//redirect to desired place since user is admin.
}
}
Best practique is whit roles, and you add role on your Routes::middleware,
Route::group(['middleware' => ['auth', 'roles:admin']], function () {
//Your routes
});
Kernel.php
'roles' => Middleware\CheckRole::class,
Create middleware
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
public function handle($request, Closure $next, ...$role)
{
if ($request->user()->hasAnyRole($role)) {
return $next($request);
}
return redirect(route('hour'));
}
}
create function on User model
public function authorizeRole($role)
{
if ($this->hasAnyRole($role)) {
return true;
}
return abort(401, 'Unauthorized.');
}
public function hasAnyRole($roles)
{
if (is_array($roles)) {
foreach ($roles as $role) {
if ($this->hasRole($role)) {
return true;
}
}
} else {
if ($this->hasRole($roles)) {
return true;
}
}
return false;
}
public function hasRole($role)
{
if ($this->role()->where('name', $role)->first()) {
return true;
}
return false;
}
public function role()
{
return $this->belongsTo('App\Role')->withDefault();
}
And Role model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
public function user()
{
return $this->hasMany('App\User');
}
}
Is more code, but best way for this action
i created a method in order to share datas with all views of my application.
For this i created a class EntityRepository where i store the datas I want to share with all views.
Those data are displayed in the layout NOT the view.
class EntityRepository
{
use App\Valuechain;
public function getEntities()
{
$vcs = Valuechain::select('valuechains.id', 'lang_valuechain.vcname', 'lang_valuechain.vcshortname')
->join('lang_valuechain', 'valuechains.id', '=', 'lang_valuechain.valuechain_id')
->join('langs', 'lang_valuechain.lang_id', '=', 'langs.id')
->where('langs.isMainlanguage', '=', '1')
->whereNull('valuechains.deleted_at')
->get();
return $vcs;
}
}
When I want to send datas to the methods I simply call the getEntities() method... For example :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
// My code here ...
return view('admin.pages.maps.sectors.index', compact('entitiesLists', 'myVars'));
}
In this specific case it works fine and i don't have issue. My issue concerns the landing page after login.
In the loginController :
I defined the redirectTo variable this way :
public $redirectTo = '/admin/home';
For specific reasons I had to override the authentificated() method in the LoginController in order to check if my app is configured or need to be setup ...
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
//return redirect()->to('admin/home');
return redirect()->action('BackOffice\StatsController#index');
}
}
The concerned index() method is sending the variable onto the view :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
return view('admin.home', compact('entitiesLists'));
}
Whatever the return i make i have error message...
Undefined variable: entitiesLists (View: C:\wamp64\www\network-dev\resources\views\admin\partials\header-hor-menu.blade.php)
I finally solved this issue by changing my routes :
Route::group(['prefix' => 'admin'], function () {
Route::get('/', function (){
$checkAuth = Auth::guard('admin')->user();
if ($checkAuth) {
return redirect('/admin/main');
}
else {
return redirect('admin/login');
}
});
});
In my loginController i changed :
public $redirectTo = '/admin/home';
to :
public $redirectTo = '/admin/main';
Finally :
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
return redirect()->to('admin/main');
}
}
My User.php
class User extends Authenticatable
{
public function sites()
{
return $this->hasMany(Site::class);
}
}
My Site.php
class Site extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
My routes.php
Route::resource('site', 'SiteController');
My SiteController.php
class SiteController extends Controller
{
public function edit(int $id)
{
$site = Auth::user()->sites()->find($id);
return view('site.edit', compact('site'));
}
}
How can I validate that the site belongs to user? I understand that in my case if site doesn't belong to user, $site variable will be null. But I want more declarative way, something like laravel requests, because I need the same check in show, update, and destroy methods. But I cannot use laravel request, because checking is something like this
$siteId = Route::current()->param('site');
$ids = Auth::user()->sites()->pluck('id')->toArray();
$result = in_array($siteId, $ids);
Can anyone suggest how to achieve my goal?
Since I use laravel 5.2, solution with route filters is deprecated. Instead route filter we should use middleware.
app/Http/Middleware/RestrictPermission.php
class RestrictPermission
{
public function handle($request, Closure $next)
{
$siteId = Route::current()->parameter('site');
if (!Auth::user()->sites()->find($siteId)) {
abort(403);
}
return $next($request);
}
}
app/Http/Kernel.php
class Kernel extends HttpKernel
{
protected $routeMiddleware = [
'restrict.permission' => RestrictPermission::class,
];
}
SiteController.php
class SiteController extends Controller
{
public function __construct()
{
$this->middleware('restrict.permission', ['except' => [
'index', 'create', 'store',
]]);
}
public function edit(int $id)
{
$site = Auth::user()->sites()->find($id);
return view('site.edit', compact('site'));
}
}