I have been trying for 8 hours or so to get Inertia.js to work with Laravel and VueJS. What I get is a blank page with no error messages in the console (both the front-end and back-end consoles actually). What I have instead is a blank page and a tab with the loading animation running infinitely.
I searched on the Internet for an answer. I have found nothing that really helps.
What I'm trying to achieve is to get a result similar to the YouTube tutorial I'm using (https://www.youtube.com/watch?v=XEW2d2XHkAk).
Here is the content of the web.php file:
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
//
Route::get("/hello", function () {
return inertia("Hello");
});
Here is the content of the app.js file:
import Vue from 'vue'
import { createInertiaApp } from '#inertiajs/inertia-vue'
import { InertiaProgress } from '#inertiajs/progress'
InertiaProgress.init()
createInertiaApp({
resolve: name => require(`./Pages/${name}`),
setup({ el, App, props }) {
new Vue({
render: h => h(App, props),
}).$mount(el)
},
})
Here is the content of the Kernel.php file:
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\HandleInertiaRequests::class,
],
'api' => [
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}
Here is the content of the app.blade.php file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link href="{{ mix('/css/app.css') }}" rel="stylesheet" />
<script src="{{ mix('/js/app.js') }}" defer></script>
</head>
<body>
#inertia
</body>
</html>
Here is the content of the Hello.vue file:
<template>
<div>hi there i am the hello page</div>
</template>
<script>
export default {};
</script>
OK. Someone I know found the answer.
So I was getting confused between these two commands:
npm run watch
versus
php artisan serve
The browser would open a tab with the app running on port 3000. So all I needed to do was to change the port in the browser. For example:
http://127.0.0.1:8000/hello
Edit: So to sum it all up, you use "npm run watch" to make sure your app is always up to date in the browser" and you run "php artisan serve" to serve your app to the browser. You run the two commands, but you have to use the port provided to you after running the "php artisan serve" command.
Related
I'm working on simple laravel9 project on my localhost where you can login via Facebook or Twitter.
I added custom domain to my localhost with verified ssl.
composer require laravel/socialite
already installed.
Facebook login works fine but twitter shows Erorr:
League\OAuth1\Client\Credentials\CredentialsException Received HTTP status code [401] with message "{"errors":[{"code":32,"message":"Could not authenticate you."}]}" when getting temporary credentials.
Here is my TwitterController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Exception;
class TwitterController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function redirectToTwitter()
{
return Socialite::driver('twitter')->redirect();
}
/**
* Create a new controller instance.
*
* #return void
*/
public function handleTwitterCallback()
{
try {
$user = Socialite::driver('twitter')->user();
$finduser = User::where('twitter_id', $user->id)->first();
if($finduser){
Auth::login($finduser);
return redirect()->intended('/home');
}else{
$newUser = User::updateOrCreate(['email' => $user->email],[
'name' => $user->name,
'twitter_id'=> $user->id,
'username'=> $user->id,
'uid' => rand(9,999999999)+time(),
'password' => encrypt('123456dummy')
]);
Auth::login($newUser);
return redirect()->intended('/home');
}
} catch (Exception $e) {
dd($e->getMessage());
}
}
}
config/services.php
'twitter' => [
'client_id' => env('TWITTER_CLIENT_ID'),
'client_secret' => env('TWITTER_CLIENT_SECRET'),
'redirect' => 'https://testsite.com/auth/twitter/callback',
],
login.blade.php
{{-- Login with Twitter --}}
<div class="mt-4 p-3 d-flex justify-content-center">
<a class="btn mr-1" href="{{ route('auth.twitter') }}"
style="background: #1D9BF9; color: #ffffff; padding: 10px; width: 30%; text-align: center; border-radius:3px;">
Twitter
</a>
</div>
routes/web.php
Route::controller(TwitterController::class)->group(function(){
Route::get('auth/twitter', 'redirectToTwitter')->name('auth.twitter');
Route::get('auth/twitter/callback', 'handleTwitterCallback');
});
.env
TWITTER_CLIENT_ID=xxxxxxxxxxxxxxxx
TWITTER_CLIENT_SECRET=xxxxxxxxxxxxxxx
composer.json
"require": {
"php": "^7.3|^8.0",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1",
"laravel/framework": "^8.75",
"laravel/sanctum": "^2.11",
"laravel/socialite": "^5.5",
"laravel/tinker": "^2.5",
"laravel/ui": "^3.4",
"socialiteproviders/twitter": "^4.1"
},
I know that my thread is duplicated but I searched alot and found that there are many people didn't find a clean solution yet.
I also tried this:
composer require socialiteproviders/twitter
as provided by laravel docs for other login providers using this https://socialiteproviders.com/Twitter/#installation-basic-usage
tried also to add providers to config/app which are not needed as I know
'providers' => [ Laravel\Socialite\SocialiteServiceProvider::class,],
'aliases' => [ 'Socialite' => Laravel\Socialite\Facades\Socialite::class,],
here is my twitter application screenshot:
Environment:staging
Solved !
App keys where somehow broken so I regenerate them.
and the other issue was misspilling in call back URL on Twitter app
this is my webpack.mix.js
const mix = require('laravel-mix');
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel applications. By default, we are compiling the CSS
| file for the application as well as bundling up all the JS files.
|
*/
mix.js('resources/js/app.js', 'public/js').vue()
.postCss('resources/css/app.css', 'public/css', [
require('postcss-import'),
require('tailwindcss'),
])
.webpackConfig(require('./webpack.config'));
if (mix.inProduction()) {
mix.version();
}
this is my app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title inertia>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght#400;600;700&display=swap">
<!-- Styles -->
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
<!-- Scripts -->
#routes
<script src="{{ mix('js/app.js') }}" defer></script>
</head>
<body class="font-sans antialiased">
#inertia
#env('local')
<script src="http://localhost:3000/browser-sync/browser-sync-client.js"></script>
#endenv
</body>
</html>
this is my web.php
<?php
use App\Http\Controllers\GoogleAuthController;
use App\Http\Controllers\KakaoAuthController;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/asdasd', function () {
return Inertia::render('Newpop');
});
Route::get('/', function () {
return view('welcome');
});
Route::post('/', function () {
return view('welcome');
});
Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Route::get('/kakao/login', [KakaoAuthController::class, 'redirect'])->name('kakao.login');
Route::get('/kakao/callback', [KakaoAuthController::class, 'callback']);
Route::get('/github/login', [GithubAuthController::class, 'redirect'])->name('github.login');
Route::get('/github/callback', [GithubAuthController::class, 'callback']);
Route::get('/google/login', [GoogleAuthController::class, 'redirect'])->name('google.login');
Route::get('/google/callback', [GoogleAuthController::class, 'callback']);
this is my Newpop.vue (it is in js/Pages folder)
<template>
<div>asdasddsdadzz</div>
</template>
<script>
export default {};
</script>
this is my app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue').default;
import {
InertiaApp
} from '#inertiajs/inertia-vue'
Vue.use(InertiaApp)
new Vue({
render: h => h(InertiaApp, {
props: {
initialPage: JSON.parse(app.dataset.page),
resolveComponent: name => import(`./Pages/${name}`).then(module => module.default),
},
}),
}).$mount(app)
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('example-two', require('./components/ExampleTwo.vue').default);
Vue.component('hu-hu', require('./components/HuHu.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
});
// require('./bootstrap');
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
import "tailwindcss/tailwind.css"
import {
InertiaProgress
} from '#inertiajs/progress'
createInertiaApp({
resolve: name => import(`./Pages/${name}`),
setup({
el,
App,
props
}) {
new Vue({
render: h => h(App, props),
}).$mount(el)
},
})
InertiaProgress.init()
when i starts php artisan serve,
my page shows only #routes.
i had changed app.js or webpack.mix.js like inertia documentation but it doesn't work.
my other vue pages (not using inertia, using js fronend scaffolding) works well.
how can i use inertia component in my project?
I have a laravel project which I have deployed on heroku. It opens when I submit the form it initially says " The information you’re about to submit is not secure " and if i still submit it, is says "419 page expired"
I tried a lot of solutions
my form sample is
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Upload File</title>
</head>
<body>
<!-- store route as action -->
<div class="container">
<div class="row">
<div class="col-12">
<br><br><br>
<form action="{{route('video')}}" method="post" enctype="multipart/form-data">
#csrf
{{ csrf_field() }}
<input type="file" class="form-control" name="videothing" id="videotitle" accept=" video/*">
<input type="submit" class="btn btn-sm btn-block btn-danger" value="Upload" onclick="spinner()">
</form>
#if (session('message'))
<h1 id="v">{{ session('message') }}</h1>
#endif
Laravel 419 Page Expired on production server. [ framework : Laravel | version : 7.5.2 ]
Laravel 6 Showed 419 | page expired
I followed these links and when I commented the
\App\Http\Middleware\VerifyCsrfToken::class,
in kernel.php, the error stops but on submitting the form it does not redirect to route rather just reloads the page,
I am sure it is CSRF issue but can't resolve it
In my VerifyCsrfToken.php, I did included
protected $except = [
//
'https://laraveluploading.herokuapp.com/',
'https://laraveluploading.herokuapp.com/video',
];
my session.php is
<?php
use Illuminate\Support\Str;
return [
'driver' => env('SESSION_DRIVER', 'file'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION', 'mysql'),
'table' => 'sessions','books','videos',
'store' => env('SESSION_STORE', null),
'lottery' => [2, 100],
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
'path' => '/',
'domain' => env('SESSION_DOMAIN', 'https://laraveluploading.herokuapp.com'),
'secure' => env('SESSION_SECURE_COOKIE',false),
'http_only' => true,
'same_site' => 'lax',
];
my web.php has
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use App\Exceptions\Handler;
use Symfony\Component\Debug\Exception\FatalThrowableError;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
})->name("start");
Route::post('/upload', function (Request $request) {
try{
if($request->file("thing")=="")
{
// return back()->withInput();
return redirect()->route('start')->with('message', 'Insert Data!');
}
else
{
$name=$request->file("thing")->getClientOriginalName();
$book=DB::table('books')->where('Title',$name)->count();
if($book>0)
{
return redirect()->route('start')->with('message', 'Document already exists!');
}
else{
$lang=$request->input("lang");
$cato=$request->input("catogory");
Storage::disk("google")->putFileAs("",$request->file("thing"),$name);
$url=Storage::disk('google')->url($name);
$details=Storage::disk("google")->getMetadata($name);
$path=$details['path'];
DB::insert('insert into books (Title, Catogory, Language, Url, FileId) values (?,?,?,?,?)', [$name,$cato,$lang,$url,$path]);
return redirect()->route('start')->with('message', 'Successfully uploaded document, you have recieved token!');
}
}
}
catch(Throwable $e)
{
return redirect()->route('start')->with('message', 'some error occured');
}
})->name("upload");
Route::get('/video', function(){
return view('showvideo');
})->name("startvideo");
Route::post('/video', function (Request $request) {
try{
if($request->file("videothing")=="")
{
// return back()->withInput();
return redirect()->route('startvideo')->with('message', 'Insert video!');
}
else
{
$videoname=$request->file("videothing")->getClientOriginalName();
$video=DB::table('videos')->where('video_name',$videoname)->count();
if($video>0)
{
return redirect()->route('startvideo')->with('message', 'Video name already exists!');
}
else{
// $lang=$request->input("lang");
// $cato=$request->input("catogory");
Storage::disk("google")->putFileAs("",$request->file("videothing"),$videoname);
$videourl=Storage::disk('google')->url($videoname);
// $videodetails=Storage::disk("google")->getMetadata($videoname);
// $path=$details['path'];
DB::insert('insert into videos (video_name, video_url) values (?,?)', [$videoname,$videourl]);
return redirect()->route('startvideo')->with('message', 'Successfully uploaded video');
}
}
}
catch(Throwable $e)
{
return redirect()->route('startvideo')->with('message', 'Some error occured in video uploading');
}
})->name("video");
in my application config var on heroku i have added the database credendtials (which is on azure) and also the google client id, secret key, refresh token required for connection with google drive.
I did tried my other solutions from different links but of no use.
Please help me resolve the issue.
I am trying to build a dataTable with custom filtering with the help of yajra datatable from here :
HTML table in view :
<form id="search-form" class="form-inline" method="POST" role="form" action="#">
<select id="batch" name="batch">
<option value="">Select</option>
<option value="22">Skill Level CBE Dec 2018</option>
<option value="2">Batch 2</option>
</select>
<button class="btn btn-primary" type="submit">Search</button>
</form>
<table class="table table-striped table-bordered datatable" cellspacing="0" width="100%">
<thead>
<tr>
<th>{{ getPhrase('S/N')}}</th>
<th>{{ getPhrase('Batch')}}</th>
<th>{{ getPhrase('Course')}}</th>
<th>{{ getPhrase('Subject')}}</th>
<th>{{ getPhrase('title')}}</th>
<th>{{ getPhrase('otq_marks')}}</th>
<th>{{ getPhrase('cr_marks')}}</th>
<th>{{ getPhrase('total')}}</th>
<th>{{ getPhrase('average')}}</th>
</tr>
</thead>
</table>
#section('footer_scripts')
#include('common.datatables', array('route'=>URL_STUDENT_EXAM_GETATTEMPTS.$user->slug, 'route_as_url' => 'TRUE'))
#stop
As to common.datatables, datatables.blade.php has :
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
tableObj = $('.datatable').DataTable({
processing: true,
serverSide: true,
retrieve :true,
// cache: true,
type: 'GET',
ajax: {
url: '{{ $routeValue }}',
data: function (d) {
d.batch = $('#batch').val();
}
}
});
$('#search-form').on('submit', function(e) {
tableObj.draw();
e.preventDefault();
});
ajax url value $routeValue refers to URL_STUDENT_EXAM_GETATTEMPTS constant (to be clarified later) used in view in whatever way.
When I select a value from the "batch" drop-down and press the submit button, an ajax call is made to the route. In browser inspection tool, I see that a lot of query parameters are added in the ajax URL and our batch param is also there. Now I need to retrieve that batch parameter inside the controller.
Now about the server side code :
The constant URL_STUDENT_EXAM_GETATTEMPTS used in blade has the value PREFIX.'exams/student/get-exam-attempts/'
And in route.php, the route is defined as :
Route::get('exams/student/get-exam-attempts/{user_slug}/{exam_slug?}', 'StudentQuizController#getExamAttemptsData');
In controller I have :
public function getExamAttemptsData(Request $request,$slug, $exam_slug = '')
{
//body goes here
}
I have used all the following methods to get the batch parameter in the controller but in vain :
$request->get('batch')
$request->query('batch')
Input::get('batch')
How can I retrieve the value of batch inside the controller ?
EDIT: BTW I am using use Illuminate\Http\Request; for the Request $request variable in controller function parameter
EDIT2: The browser inspection tool shows the ajax request url as :
http:// localhost/lcbs/exams/student/get-exam-attempts/myuser123 ?draw=2&columns%5B0%5D%5Bdata%5D=0......search%5Bregex%5D=false&batch=22&_=1541684388689.
So you see that batch is there in the query parameters.
But inside the controller, the code $request->getQueryString() only shows
%2Fexams%2Fstudent%2Fget-exam-attempts%2Fmyuser123
And \URL::current() shows http:// localhost/lcbs/exams/student/get-exam-attempts/myuser123
That means, the $request misses the complete query string.
EDIT3: # Adrian Hernandez-Lopez, I am pasting the FULL content of Kernel.php here :
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'role' => \Zizaco\Entrust\Middleware\EntrustRole::class,
'permission' => \Zizaco\Entrust\Middleware\EntrustPermission::class,
'ability' => \Zizaco\Entrust\Middleware\EntrustAbility::class,
// 'adminOrGuest' => \App\Http\Middleware\AdminOrGuestMiddleware::class,
];
}
Looks like the ? in the Route is not used to define an optional parameter but a string instead:
Route::get('exams/student/get-exam-attempts/{user_slug}/{exam_slug?}', 'StudentQuizController#getExamAttemptsData');
Could you please change it and see what you get?
Route::get('exams/student/get-exam-attempts/{user_slug}/{exam_slug}', 'StudentQuizController#getExamAttemptsData');
Also, the query string you posted has a space after myyser123, this could also explain the issue.
http:// localhost/lcbs/exams/student/get-exam-attempts/myuser123 ?draw=2&columns%5B0%5D%5Bdata%5D=0......search%5Bregex%5D=false&batch=22&_=1541684388689.
So I would suggest to check how the value is defined in the javascript code
url: '{{ $routeValue }}',
I've used redirect back with input many times previously. But in this project I'm unable to do so. This is my controller method that handles the form request:
public function verifyMobileCode( Request $request)
{
$userId = Auth::user()->id;
if( Auth::user()->verification_code == $request['verification_code'])
{
User::where('id', $userId)->update(['verified'=>1]);
return redirect('/')->with('success', 'Account verified.');
}
else
{
return redirect()->back()->withErrors('verification_code' ,'unv' )->withInput($request->all());
}
}
This is my form blade:
#extends('layouts.index')
#section('content')
<div class="container" style='padding-top: 150px;'>
<?php var_dump($errors) ; ?>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Verify your mobile</div>
<div class="panel-body">
<form class="form-horizontal" method="POST" action="{{ route('verifyMobileCode') }}">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('verification_code') ? ' has-error' : '' }}">
<label for="verification_code" class="col-md-4 control-label">Verification code</label>
<div class="col-md-6">
<input id="verification_code" type="text" class="form-control" name="verification_code" value="{!! old('verification_code') !!}" required autofocus maxlength="6" pattern="\d{6}">
#if ($errors->has('verification_code'))
<span class="help-block">
<strong>Please enter 6 digit number sent to your mobile.</strong>
</span>
#endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Register
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
#endsection
My Kernel.php is as follows:
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::class,
\App\Http\Middleware\LanguageSwitcher::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'is-admin' => \App\Http\Middleware\IsAdminMiddleware::class,
];
}
I do not find any error or something wrong. Is there anything you see? Is there any technique to debug this behaviour? Thaks in advance.
My approach would be using FormRequest.
php artisan make:request VerifyCodeRequest
And body of the request:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class VerifyCodeRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'verification_code' => 'required|in:'.$this->user()->verification_code, // since user is already logged in we check if verification_code matches using `in` rule
];
}
public function messages()
{
return [
'in' => 'Your custom error message if we failed',
];
}
}
Now you change signature of verifyMobileCode(...) to the following verifyMobileCode(App\Http\Requests\VerifyCodeRequest $request).
Now, code executes body of the function only if we pass the validation so we need to update user instance and we are done.
public function verifyMobileCode(App\Http\Requests\VerifyCodeRequest $request)
{
$request->user()->verify();
return redirect('/')->with('success', 'Account verified.');
}
Inside User model add verify() function
public function verify()
{
$this->update(['verified' => true]);
}
If your above approach does not work the there is some issue with your app/Http/Kernel.php. You have used
\Illuminate\Session\Middleware\StartSession::class,
twice. You must delete one. Probably the first one.
See the stock Laravel's kernel.php.
Replace ->withInput($request->all()); with ->withInput();
if you dont want any one of the input use
->withInput(
$request->except('input_name')
);
To debug this without resorting to Xdebug the quick way is to add temporary debug code to the start of the blade file:
#php
dd($errors->toArray(), $errors->has('verification_code'));
#endphp
Which will give you the following output:
array:1 [
0 => array:1 [
0 => "verification_code"
]
]
false
This shows that the logic in the blade file is not being evaluated to true which is required to show the error styles and message.
The quick fix is to change the controller to use:
->withErrors(['verification_code' => 'unv'])
withErrors expects as MessageBag or array, but will cast a string to an array which does not result in the proper key/value pair.
The debug output will now show:
array:1 [
"verification_code" => array:1 [
0 => "unv"
]
]
true
The debug code can now be removed and the error should be displayed as you expect.
The proper Laravel way is probably to use $request->validate() or a FormRequest for complex forms. For more information see the Laravel validation documentation (https://laravel.com/docs/5.5/validation).
Your Controller should look like this:
public function verifyMobileCode( Request $request)
{
$userId = Auth::user()->id;
if( Auth::user()->verification_code == $request['verification_code'])
{
User::where('id', $userId)->update(['verified'=>1]);
return redirect('/')->with('success', 'Account verified.');
}
else
{
return redirect()->back()->withErrors('message' ,'Please some errors encountered.' );
}
}
And modify this
<div class="form-group{{ $errors->has('verification_code') ? ' has-error' : '' }}">
To this:
<div class="form-group>
#include('errors');
Also create file called errors.blade.php in resources/views and put the following code:
#if ($errors->any())
<div class="card"> //incase bootstrap 4
<div class="error card-body alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
</div>
#endif
Hope it works for you. But you dont need to display old inputs since the code will be wrong or something wrong has happened. So its not necessary
return redirect()->back()->withInput()->withErrors('verification_code' ,'unv' );
In controller
return redirect()->back()->withErrors('verification_code' ,'unv')->withInput();
In view
if you want to retrieve the validated input field value then you need to use laravel FORM class for <form></form> as well as <input> fields
example
{{ Form::open(['method' => 'post','url' => 'Your url','class'=>'form-horizontal']) }}
{{ Form::text('verification_code','',['class'=>'form-control']) }}
{{ Form::close() }}
anybody on Laravel 8, this should work
return back()->withErrors('your error message is here');
If you look at the signature of the withErrors function, second param is the key and it is set to default unless you want it to be something specific.