How can I use custom error messages in a json response? I'm using Ajax to validate a login form in frontend and I've already manage how to display the Validator errors, but I can't figure out how I can retrieve a custom error message.
This is the controller:
public function LoginValid(Request $request){
$validator = Validator::make($request->all(), [
'email' => ['required', 'string', 'email' ],
'password' => ['required', 'string', 'max:255'],
]);
if($validator->passes()){
$user = User::where('email', $request->email)->first();
if ($user &&
Hash::check($request->password, $user->password)) {
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
return redirect()->intended('dashboard');
}else{
return response()->json('should be any custom message here');
}
}
}else{
return response()->json(['error'=>$validator->errors()->all()]);
}
}
And here's the Ajax:
$(document).ready(function() {
$("#btn-login").click(function(e) {
e.preventDefault();
var _token = $("input[name='_token']").val();
var email = $("input[name='email']").val();
var password = $("input[name='password']").val();
$.ajax({
url: "{{ route('login-valid') }}",
type: 'POST',
data: { _token: _token, email: email, password:password },
success: function(data) {
if ($.isEmptyObject(data.error)) {
window.location.href = 'dashboard';
} else {
printErrorMsg(data.error);
}
}
});
});
function printErrorMsg(msg) {
$(".print-error-msg").find("ul").html('');
$(".print-error-msg").css('display', 'block');
$.each(msg, function(key, value) {
$(".print-error-msg").find("ul").append('<li>' + value + '</li>');
});
}
});
you can customize validation messages in this way. I am using your code for an example.
$validator = Validator::make($request->all(), [
'email' => ['required', 'string', 'email' ],
'password' => ['required', 'string', 'max:255'],
], [
'email.required' => 'email is required',
'email.string' => 'email should be valid',
'email.email' => 'email should be in proper format'
.
.
.
.
and so on
]);
above code will overwrite the laravel default messages.
Related
I have below type of json in my laravel request, I want to validate json object key in my laravel request file. I want to validate title value is required of data json. I found solution but it's for controller, I want to validate it in my request file
{"ID":null,"name":"Doe","first-name":"John","age":25,"data":[{"title":"title1","titleval":"title1_val"},{"title":"title2","titleval":"title2_val"}]}
Why not use Validator
$data = Validator::make($request->all(), [
'ID' => ['present', 'numeric'],
'name' => ['present', 'string', 'min:0'],
'first-name' => ['present', 'string', 'min:0',],
'age' => ['present', 'numeric', 'min:0', 'max:150'],
'data' => ['json'],
]);
if ($data->fails()) {
$error_msg = "Validation failed, please reload the page";
return Response::json($data->errors());
}
$json_validation = Validator::make(json_decode($request->input('data')), [
'title' => ['present', 'string', 'min:0']
]);
if ($json_validation->fails()) {
$error_msg = "Json validation failed, please reload the page";
return Response::json($json_validation->errors());
}
public function GetForm(Request $request)
{
return $this->validate(
$request,
[
'title' => ['required'],
],
[
'title.required' => 'title is required, please enter a title',
]
);
}
public function store(Request $request)
{
$FormObj = $this->GetForm($request);
$FormObj['title'] = 'stackoveflow'; // custom title
$result = Project::create($FormObj); // Project is a model name
return response()->json([
'success' => true,
'message' => 'saved successfully',
'saved_objects' => $result,
], 200);
}
I get the following error when logging in with my mobile phone:
Uncaught (in promise) Error: Request failed with status code 422
how can i fix this?
My Controller
public function login(Request $request)
{
$req = Request::create(route('passport.token'), 'POST', [
//'grant_type' => 'password',
'client_id' => 2,
'client_secret' => '326g3KM3giN4o3UHITByxPLHaZlWzqfZbWs0vWLd',
'phone_number' => $request->phone_number,
//'password' => $request->password,
]);
$response = app()->handle($req);
if ($response->status() == 400) {
return response()->json([
'message' => ''
]);
} else if ($response->status() == 401) {
return response()->json([
'message' => ''
]);
}
return $response;
I also redefined functions in the user model
public function findForPassport($identifier) {
return $this->where('phone_number', $identifier)->first();
}
public function validateForPassportPasswordGrant($password)
{
return true;
}
I've read your description. So, you have to store phone and code in the table users. To simplify it, you can store code in DB field password as an encrypted value.
$user->phone_number = $request->phone_number;
$user->password = bcrypt($code);
And then during login you can use your own code:
$req = Request::create(route('passport.token'), 'POST', [
'grant_type' => 'password',
'client_id' => 2,
'client_secret' => '326g3KM3giN4o3UHITByxPLHaZlWzqfZbWs0vWLd',
'phone_number' => $request->phone_number,
'password' => $request->code,
]);
$response = app()->handle($req);
I want to implement Passport authentication in Laravel. this is the register function:
public function register(Request $request)
{
$credentials = $request->only('name', 'email', 'password');
$rules = [
'name' => 'required|max:100',
'email' => 'required|email|max:120|unique:users',
'password' => 'required',
];
$validator = Validator::make($credentials, $rules);
if($validator->fails()) {
return response()->json(['success'=> false, 'error'=> $validator->errors()]);
}
$user = User::create(['name' => $request->name, 'email' => $request->email, 'password' => bcrypt($request->password)]);
if(Auth::attempt($credentials)){
$user = Auth::guard('api')->user();
$data['id'] = $user->id;
$data['name'] = $user->name;
$data['phone'] = $user->phone;
$data['token'] = $user->createToken('API')->accessToken;
return response()->json([
'success'=> true,
'data'=> $data
]);
}
return response()->json([
'success'=> false,
'data'=> $response
]);
}
and this is my routes:
Route::post('register', 'Api\AuthController#register');
Route::middleware('auth:api')->get('/user', function (Request $request) {
return response()->json($request->user());
});
I want to display the user information in postman, and this is the request header to the url: http://127.0.0.1:8004/api/user:
Accept:application/json
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiOThjYjM0YjkzOWJhMzczMDEwMGI0NmEyNTBhOGEzYTc5MTAyMjI1M2E2OTM0OGY0NGU1YWU4Njg3MzZkYmVlZjNlNzI1MDNiZTRhMjE5NGUiLCJpYXQiOjE1ODQ1NDczMDcsIm5iZiI6MTU4NDU0NzMwNywiZXhwIjoxNjE2MDgzMzA3LCJzdWIiOiI1NyIsInNjb3BlcyI6W119.GcqelFT2d3kKi8fR2vNbgMB1Fe_sQjrd2Mb3cRQLbS20IR_445bcTbcl17yKJrldboFktobeSIHx1GQENIzQbO0RStysmisiKuLk8eoXUvNVJq3t1bpZrjPBiNEGDRPqezq5VEsGhotVgbKRLK1gbVHwvE7mtSuGQTp9nIf6PEsmiJLsGmUJ0GdCmWXXLvJ0dBac1DZ_KauppDs_Lymx9SEXgzTDW60rpYrwHNbbaLfa6wdW3M5tUZM3vMRcKhCgYitvK_DfttKHcWqvEX8_lZT0h5GcQSsori_K8Lj_ynKfjrTfbodUKzT4kDZ8z-RnE4-SgG75LWDeqcpDRhuDmiL0KTIzwtrNFtU0NEo-v0t6dTkAuJCl1ZnTT72sLZoI6rsTPHtNKIDxwN9VrXiTU5pxGEc6ju5e30NQnkjBRjMRsVIcCHR-WohObuWkZOGRq-RP5on3oiLe2VGk0PENXXziMX3D5urpLWK3WR-ZY0Bz3fKitgE8TFaT1cOMSyK6d3zskUEdMjDyLCxbS7vKhmNuAy2moOj7f7DI9yr8XNeyF00WJKw0WJi76XX_Y06O-VtNhqzgeEyu6QM6qRivpBBcj-WkdbSTmveNZlSqAesLm6WD8qWKc9FR-S_41fCc2qLEY_VOotSA8tOYASVKpdsvj2liTbbMH9905HQJe-o
Content-Type:application/json
but the result is always:
{
"message": "Unauthenticated."
}
How could I display user information? thanks in advance
Change
Auth::attempt($credentials)
to
Auth::guard('api')->attempt($credentials)
I am creating a new app using Cashier 10.1. In the past I would send a token from Stripe to the subscription function when registering a user with a subscription. Now it says it takes a Payment Method (id). I am registering a payment method with Stripe and passing that to my controller but it returns the error "This customer has no attached payment source". I read the docs but it only gives an example of how to add a subscription to a current user by passing to the view $user->createSetupIntent(). Below is the code for when a user registers:
Component
pay() {
this.isLoading = true;
if (this.form.payment_method == "cc") {
let that = this;
this.stripe
.createPaymentMethod({
type: "card",
card: that.card
})
.then(result => {
this.form.stripePayment = result.paymentMethod.id;
this.register();
})
.catch(e => {
console.log(e);
});
} else {
this.register();
}
},
register() {
this.form
.post("/register")
.then(data => {
this.isLoading = false;
if (data.type == "success") {
this.$swal({
type: "success",
title: "Great...",
text: data.message,
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 2000
});
setTimeout(() => {
// window.location.replace(data.url);
}, 2000);
}
})
.catch(error => {
this.isLoading = false;
});
}
RegisterController
protected function create(request $request)
{
$request->validate([
'name' => 'required',
'email' => 'required|unique:users',
'username' => 'required|alpha_dash|unique:users',
'phone' => 'required',
'city' => 'required',
'state' => 'required',
'password' => 'required|confirmed',
'agree' => 'required',
]);
$user = User::create([
'username' => $request['username'],
'name' => $request['name'],
'email' => $request['email'],
'phone' => $request['phone'],
'city' => $request['city'],
'state' => $request['state'],
'password' => Hash::make($request['password']),
]);
if ($request['subscription_type'] == 'premier' && $request['payment_method'] == 'cc') {
$user->newSubscription('default', env('STRIPE_PLAN_ID'))->create($request->input('stripePayment'), [
'email' => $request['email'],
]);
}
if ($user) {
$user->assignRole('subscriber');
Auth::login($user);
return response()->json([
'type' => 'success',
'message' => 'you are all set.',
'url' => '/dashboard'
]);
}
I found a good article explaining the new setup finally. Basically when I show my registration view I now create a new User and pass the intent there. I kept thinking the user had to be saved already, not just created. So if anyone else wants to do it:
Show the view
Registration Controller
public function show()
{
$user = new User;
return view('auth.register', [
'intent' => $user->createSetupIntent()
]);
}
Pass the intent to my Vue component
<register-form stripe-key="{{ env('STRIPE_KEY') }}" stripe-intent="{{ $intent->client_secret }}">
</register-form>
Add stripe elements to a div:
mounted() {
// Create a Stripe client.
this.stripe = Stripe(this.stripeKey);
// Create an instance of Elements.
var elements = this.stripe.elements();
var style = {
base: {
color: "#32325d",
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#aab7c4"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a"
}
};
// Create an instance of the card Element.
this.card = elements.create("card", { style: style });
// Add an instance of the card Element into the `card-element` <div>.
this.card.mount("#card-element");
},
process the data
pay() {
this.isLoading = true;
if (this.form.payment_method == "cc") {
this.setupCard();
} else {
this.register();
}
},
setupCard() {
this.stripe
.handleCardSetup(this.stripeIntent, this.card, {
payment_method_data: {
billing_details: { name: this.form.name }
}
})
.then(data => {
this.form.stripePayment = data.setupIntent.payment_method;
if (this.form.stripePayment) this.register();
})
.catch(error => {
this.isLoading = false;
console.log(error);
});
},
register(setupIntent) {
this.form
.post("/register")
.then(data => {
this.isLoading = false;
if (data.type == "success") {
this.$swal({
type: "success",
title: "Great...",
text: data.message,
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 2000
});
setTimeout(() => {
window.location.replace(data.url);
}, 2000);
}
})
.catch(error => {
this.isLoading = false;
});
}
Save the user
Registration Controller
protected function create(request $request)
{
$request->validate([
'name' => 'required',
'email' => 'required|unique:users',
'username' => 'required|alpha_dash|unique:users',
'phone' => 'required',
'city' => 'required',
'state' => 'required',
'password' => 'required|confirmed',
'agree' => 'required',
]);
$user = User::create([
'username' => $request['username'],
'name' => $request['name'],
'email' => $request['email'],
'phone' => $request['phone'],
'city' => $request['city'],
'state' => $request['state'],
'password' => Hash::make($request['password']),
]);
if ($request['subscription_type'] == 'premier' && $request['payment_method'] == 'cc') {
$user->newSubscription('default', env('STRIPE_PLAN_ID'))->create($request->input('stripePayment'), [
'email' => $request['email'],
]);
}
if ($user) {
$user->assignRole('subscriber');
Auth::login($user);
return response()->json([
'type' => 'success',
'message' => 'you are all set.',
'url' => '/dashboard'
]);
}
}
Cashier has updated the way it interacts with Stripe due to Strong Customer Authentication (SCA). This means card payments require a different user experience, namely 3D Secure, in order to meet SCA requirements. It may be beneficial to read-up on the Payment Intents API on Stripe and you may be able to work around this by first creating the payment intent with a direct interaction with Stripe and then attaching it to your Laravel user.
The simple solution may be to have a multi step registration process:
Step 1: Collect customer details and create user on Laravel and Stripe
Step 2: Create the payment intent $user->createSetupIntent() and collect payment details and save to customer.
Step 3: Subscribe user to the Cashier Plan
when i try to submit a form with Ajax,i get this Error,MethodNotAllowedHttpException No message.
i guess problem is in routing, but when i tested without Ajax it works fine
here is my Ajax code:
$.ajax({
method: 'POST',
url: "{{ route('submitProfile') }}",
dataType: 'json',
data: {_token: CSRF_TOKEN, firstName:firstName, lastName:lastName, email:email, mobile:mobile},
success: function( data ) {
console.log(data);
}
});
my route is:
Route::get('/edit/profile',[
'uses' => 'UserController#getEditProfile',
'as' => 'editProfile'
]);
Route::post('/ajax/edit/profile',[
'uses' => 'UserController#postEditProfile',
'as' => 'submitProfile'
]);
and in my controller i have this functions:
public function postEditProfile(Request $request)
{
$this->validate($request,[
'firstName' => 'required',
'lastName' => 'required',
'email' => 'required|email',
'mobile' => 'required',
]);
$user = \Auth::user();
$user->firstName = $request['firstName'];
$user->lastName = $request['lastName'];
$user->email = $request['email'];
$user->mobile = $request['mobile'];
$user->save();
return response()->json([
'status' => 'its done!'
]);
}
thank you.
Can you try this for your route
Route::post('/ajax/edit/profile',[
'uses' => 'UserController#postEditProfile'
])->name('submitProfile');