Same route, different page for authenticated user or not - laravel

I want to display either welcome.blade.php or login.blade.php with the same base url / (because the login is in the main page)
Is this a good convention to check it in the web.php:
Route::get('/'), function () {
if (auth()->check()) {
// return the welcome.blade.php view
} else {
// return the login.blade.php view
}
}
Or I should do this in a different place?

Separation of concern ! It means that whatever the module/method you write should be pure from side effects and has only one job.
web.php in routes directory serves all the routes file. So if you try to put the business logic here, it will still work but it will violate the standard of framework. All business logic either should go to controllers , helpers and all the authentication related stuff should go to middlewares. Therefor, we should handle this logic inside the controllers if it is specific to single route. In our case /. Otherwise if we have to handle generic authentication stuff, we should go into middleware.
Therefor, the flow would look something like this
User hit the route /
Through the web.php, it redirected to particular controller let say HomeController.
Inside the HomeController , you will put the same condition and render the view accordingly. i.e
if (auth()->check()) {
// return the welcome.blade.php view
} else {
// return the login.blade.php view
}
We can achieve the same thing in web.php but it will not be according to the framework standard. Further, If you have to do more stuff other than just rendering view, it will get more complicated in web.php.
I hope it will answer your question.
Thanks,

Related

Laravel Livewire how to redirect before render

I want to redirect if Auth::user()->id is not equal to Ad->user_id
it does not work inside the mount or hydrate method.
$this->ad = Ad::where('id', $this->ad_id);
if ($this->ad->user_id != Auth::User()->id) {
return redirect()->route('dashboard');
}
You can redirect from mount() method. You can't redirect inside render as you would need to call return redirect('/') which would throw an error "render" method on [App\Http\Livewire\...] must return instance of [Illuminate\View\View]
function mount(){
if(condition fails){
return redirect()->to('someplace');
}
}
Livewire does not do backend redirects as far as I experienced, but rather uses JS to do them. So if you use the $this->redirect method, it will tell rendered component to perform the redirect. Some solutions I've seen on the web were in the render function, if you have an issue that results in a redirect being required, create an empty blade file with a simple div inside, and everywhere you need to redirect the user, set the render view as the blank one, and the FE will take the redirect. A pretty messy fix, but I did not see any better ones currently.
I tried everything but below-mentioned trick worked for me.
Rather than routing from the livewire component we can route from the livewire blade component by adding below code.
#php
$carts = \Cart::getContent();
if(count($carts) == 0)
{
$this->redirect('/shopping-cart/bag');
}
#endphp
Suggestions:
Don't use "return" while redirecting otherwise you might face some Front-end issues.
Don't use "route" while redirecting otherwise the code won't work.

Laravel routes with vue/vue router

I'm basically using VueRouter to create all my routes which is working really well. However, my application is built using Laravel. So if I refresh any of the routes I get an error that the route is not defined. So at the minute in every controller I've had to add an index function. This just returns the view of my app.blade which is just the usual tags etc and the to load my single page app. I'm just wondering if there is a cleaner solution? I guess I could move the return view into a single Controller and make my Controllers extend this. But I'm just wondering if there is a better way I'm missing?
i.e. one of my routes via VueRouter:
{
path: "/clients",
name: "clients",
component: () => import(/* webpackChunkName: "clients" */ "../resources/js/components/Views/Clients/Clients.vue")
},
The route in my clients.php file
Route::get('/clients', [App\Http\Controllers\ClientController::class, 'index'])->name('clients');
Then the ClientController index function
public function index()
{
return view('app');
}
It would just be nice to have the loading of the app.blade done somewhere else and not need to be specified per controller. Any help would be appreciated to ensure it's all done efficiently!
Thanks!
Here is how I solved this issue for one of my projects which is also single page application in Vue and Laravel: https://github.com/lyyka/laravel-vue-blog-spa/blob/master/routes/web.php
Simply, in your routes file, you put this code:
Route::get('/{any}', function () {
return view('welcome');
})->where("any", ".*");
And in my welcome view I have:
#extends('layouts.app')
#section('content')
<div class = "container">
<router-view></router-view>
</div>
#endsection
Basically this will return your app view for any URL and so your Vue SPA should work properly. Generally, it is not a good practice to put callback functions inside your routes file, but in this case, you won't even be using your routes file as it is a SPA, so this solution can pass! :)
You should use your single html file and make a controller.
On your controller
public function index(){
return view('index');
}
on your web.php
basically, you should make the same route on your laravel and vue
Route::get('/products', [ProductsController::class,'index']);
in my vue-routes
import Products from './components/Products.vue'
{
path:'/products'
component: Products
}

Redirect from method in Vue.js with Vue-router older than version 1.x.x

I'm not much of a frontend developer but I know enough javascript to do the minimum.
I'm trying to plug into a last piece of login however my vue components are:
"vue-resource": "^0.9.3",
"vue-router": "^0.7.13"
I'm not experienced enough to move up to v1 or v2 respectively.
I would like to achieve something similar to this.
However I'm not getting a successful redirect.
my app.js file:
var router = new VueRouter();
...
import Auth from './services/auth.js';
router.beforeEach(transition => {
if(transition.to.auth &&!Auth.authenticated)
{
transition.redirect('/login');
}
else
{
transition.next();
}
});
```
In my login.js file
```
methods: {
/**
* Login the user
*/
login(e) {
e.preventDefault();
this.form.startProcessing();
var vm = this;
this.$http.post('/api/authenticate',
{ email : this.form.email,
password : this.form.password
})
.then(function(response){
vm.form.finishProcessing();
localStorage.setItem('token', response.data.token);
vm.$dispatch('authenticateUser');
},
function(response) {
if(response.status == 401)
{
let error = {'password': ['Email/Password do not match']};
vm.form.setErrors(error);
}else{
vm.form.setErrors(response.data);
}
});
}
}
I tried to do as suggested:
vm.form.finishProcessing();
localStorage.setItem('token', response.data.token);
vm.$dispatch('authenticateUser');
vm.$route.router.go('/dashboard');
However all it did was append the url on top.
I see that the 3 previous events were successfully done but not the redirect.
it went from:
http://dev.homestead.app:8000/login#!/
to
http://dev.homestead.app:8000/login#!/dashboard
when I need the entire page to go to:
http://dev.homestead.app:8000/login/dashboard#1/
I think i have a missing concept in order to do the redirect correctly.
UPDATE
As per suggested i have added param: append => false but nothing happens.
what i did afterward was within app.js create a method called redirectLogin() with console.log() outputs - that worked. what i did further is i put vm.$route.router.go inside there and called the method via vm.$dispatch('redirectLogin'); and that also didn't work.
NOTE:
The HTML is being rendered in Laravel first. the route I originally had (and working) as login/dashboard and that route is available via normal Laravel route. the blade is being rendered via view template.
So far I've been trying to vue redirect over to login/dashboard (not working) perhaps I should somehow remove login/dashboard and use the route.map and assign login/dashboard?
I would rather keep the login/dashboard as a laravel route due to authentication and other manipulation.
For Vue 2
this.$router.push('/path')
As par the documentation, router.go appends the path in the current route, however in your case it is appending along with # in the router as well.
You can use param: append, to directly arrive at your desired destination, like following:
vm.$route.router.go({name: '/login/dashboard#1/', params: {append: false}})
Edited
If it is not happening, you can try $window.location method like following:
var url = "http://" + $window.location.host + "login/dashboard";
console..log(url);
$window.location.href = url;
I think their is a misunderstanding here of how vue-router works. It seems you are not wanting to load a new route with a corresponding component, rather you simply want to redirect to a new page then let that page load and in turn fire up a fresh instance of vue.
If the above is correct you don't need vue-router at all. Simply add the below when you need to load the page:
window.location.href = '/login/dashboard'
If you'd rather simulate a redirect to that page (no back button history) then:
window.location.replace('/login/dashboard')
EDIT
The above would be fired when you have finished all processing that the page must run to set the users state which the next page requires. This way the next page can grab it and should be able to tell the correct state of the user (logged in).
Therefore you'll want to fire the redirect when the Promise has resolved:
.then(function(response){
vm.form.finishProcessing()
// store the Auth token
localStorage.setItem('token', response.data.token)
// not sure whether this is required as this page, and in turn this instance of vue, is about to be redirected
vm.$dispatch('authenticateUser')
// redirect the user to their dashboard where I assume you'd run this.$dispatch('authenticateUser') again to get their state
window.location.replace('/login/dashboard')

Yield section if a certain controller is used

In my Laravel layout, I would like to display a menu bar if a certain controller is used.
How would I detect a controller inside blade?
For example:
// Layout main.blade.php
if(Controller == admin){
#yield('menu')
}
I know the syntax is wrong. Just to give you an idea what I'm trying to do.
There's a package for that: https://github.com/digithis/activehelper. It explains in detail how you can use it and it has helped me to do the same as what you're asking.
For a one-liner, you can use Route::currentRouteAction() assuming your routes are configured for example as:
Route::get('test', array('as'=>'test', 'uses'=>'TestsController#test'));
Very concrete for your question, you can use:
if (explode( '#' , Route::currentRouteAction())[0]) == 'controllerName')
{
// your code here
}

Laravel4: double post route

Sorry if can sound strange, but in the routes, on the post of my view I need to do two operations:
Route::post('booking', 'HomeController#booking');
Route::post('booking', function()
{
return Queue::marshal();
});
But of course doing this I get an error: Invalid data.
Yet for the post of the view 'booking' I need to call the method of the controller, and at the same time return Queue::marshal()
There is perhaps I can do this?
Thank you very much!
EDIT:
Here is the HomeController#booking method:
http://paste.laravel.com/19ej
If you define two routes with the same verb and url, the second one is never going to be fired.
Route::post('booking', 'HomeController#booking'); // Laravel will find this route first
Route::post('booking', function() // so this function will never be executed
{
return Queue::marshal();
});
I see that your HomeController#booking() is handling a form. Why can you just use another route for this?
Route::post('booking/create', 'HomeController#booking');
And then change your form action method to point to this route:
// this will render <form method="POST" action="http://yourdomain.com/booking/create"
{{ Form::open(array('action' => 'HomeController#booking')) }}
This way you don't have one route overlapping the other.
Some advice unrelated to the question. Taking a look at your controller, I have noticed that you do this when checking for errors:
if ( ! $errorCondition) {
// do stuff
} else {
// show errors
}
Your code will be a lot easier to read if you write it like this:
if ($errorCondition) {
// return error
}
// do stuff

Resources