Aaaargh, I want "onResponse", not "onFailure" [closed] - php

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 days ago.
Improve this question
I have made the registration fragment in my android project.
And I'm using laravel as api of the project.
This is code of the RegistrationFragment.kt :
package com.alifandegar.registration
import android.app.DatePickerDialog
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import com.alifandegar.registration.databinding.FragmentRegistrasiBinding
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.text.SimpleDateFormat
import java.util.*
class RegistrasiFragment :Fragment(), View.OnClickListener {
private val api by lazy { API.create() }
private var cal = Calendar.getInstance()
private val loading by lazy { MyLoading(requireActivity() as LoginActivity) }
private var _binding : FragmentRegistrasiBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentRegistrasiBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.submitRegister.setOnClickListener {
val nm_lengkap = binding.inputNamaLengkap.text.toString()
val tmp_lahir = binding.inputTempatLahir.text.toString()
val tgl_lahir = binding.inputTanggalLahir.text.toString()
val no_hp = binding.inputnoHp.text.toString()
val email = binding.inputEmail.text.toString()
val buat_password = binding.inputPassword.text.toString()
val konfirmasi_password = binding.inputKonfirmasiPasword.text.toString()
if (nm_lengkap.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
else if (no_hp.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
else if (tmp_lahir.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
else if (tgl_lahir.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
else if (email.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
else if (buat_password.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
else if (konfirmasi_password.isEmpty()){
binding.inputNamaLengkap.error = "This field cannot be null!"
}
loading.show()
api.simpan(
nm_lengkap,
tmp_lahir,
tgl_lahir,
no_hp,
email,
buat_password,
konfirmasi_password
).enqueue(object : Callback<Simpan> {
override fun onResponse(call: Call<Simpan>, response: Response<Simpan>) {
loading.dismiss()
val result = response.body()
if (result != null){
if (result.response_code == 200) {
Toast.makeText(
requireActivity(),
result.message,
Toast.LENGTH_SHORT
).show()
} else {
binding.inputEmail.error = result.detailError.email
binding.inputPassword.error = result.detailError.buat_password
binding.inputKonfirmasiPasword.error = result.detailError.konfirmasi_password
Toast.makeText(
requireActivity(),
"Sorry, your field isn\'t correct. Please check your field again.",
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onFailure(call: Call<Simpan>, t: Throwable) {
loading.dismiss()
Log.d("RegistrationActivity", "onFailure: ${t.message} ")
Toast.makeText(
requireActivity(),
"oops, there\'s wrong up there...",
Toast.LENGTH_LONG
).show()
}
})
}
binding.inputTanggalLahir.setOnClickListener(this)
}
private fun updateLabel() {
val myFormat = "yyyy/MM/dd"
val dateFormat = SimpleDateFormat(myFormat, Locale.US)
binding.inputTanggalLahir.setText(dateFormat.format(cal.time))
}
override fun onClick(v: View?) {
val date =
DatePickerDialog.OnDateSetListener { _, year, month, day ->
cal.set(Calendar.YEAR, year)
cal.set(Calendar.MONTH, month)
cal.set(Calendar.DAY_OF_MONTH, day)
updateLabel()
}
DatePickerDialog(
requireActivity(),
date,
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH)
).show()
}
}
And this is the code of API.kt
package com.alifandegar.registration
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
interface API {
#FormUrlEncoded
#POST("api/login")
fun login(
#Field("email") email: String,
#Field("password") password : String
) : Call<LoginModel>
#FormUrlEncoded
#POST("api/simpanregistrasi")
fun simpan(
#Field("nm_lengkap") nm_lengkap: String,
#Field("tmp_lahir") tmp_lahir: String,
#Field("tgl_lahir") tgl_lahir: String,
#Field("no_hp") no_hp: String,
#Field("email") email: String,
#Field("buat_password") buat_password: String,
#Field("konfirmasi_password") konfirmasi_password: String
) : Call<Simpan>
companion object {
fun create() : PPDBAPI {
val httpClient = OkHttpClient.Builder()
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
httpClient.addInterceptor(logging)
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://10.0.2.2:8000/")
/*.baseUrl("http://172.16.1.31:8000/")*/
.client(httpClient.build())
.build()
return retrofit.create(PPDBAPI::class.java)
}
}
}
And this is the code of Simpan.kt (Model):
package com.alifandegar.ppdbdarel_ilmipayakumbuh
data class Simpan (
val response_code: Int,
val message: String,
val detailError: ListError
){
data class ListError(
val nm_lengkap: String,
val tmp_lahir: String,
val tgl_lahir: String,
val no_hp : String,
val email: String,
val buat_password: String,
val konfirmasi_password: String,
)
}
And, I'm using Validation in the laravel project such as like this:
Code of project/app/Request/RegistrationRequest.php (as validator request) :
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Contracts\Validation\Validator;
class LoginRequest extends FormRequest
{
public function rules()
{
return [
'nm_lengkap' => 'required',
'tmp_lahir' => 'required',
'tgl_lahir' => 'required',
'no_hp' => 'required',
'email' => 'required|email|unique:users,email',
'buat_password' => 'required|min:8',
'konfirmasi_password' => 'required|same:buat_password',
];
}
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(response()->json([
'response_code' => 404,
'message' => 'Error! : ',
'detailError' => $validator->errors(),
]));
}
public function messages()
{
return [
'nm_lengkap.required' => 'Field \'Nama Lengkap\' is required!!',
'tmp_lahir.required' => 'Field \'Tempat Lahir\' is required!!',
'tgl_lahir.required' => 'Field \'Tanggal Lahir\' is required!!',
'no_hp.required' => 'Field Nomor HP is required!!',
'email.required' => 'Field Email is required!!',
'email.unique' => 'The email has been used by another user, please change your email account.',
'buat_password.required' => 'Field password is required!!',
'buat_password.min' => 'The password cannot be less than 8 words',
'konfirmasi_password.required' => 'Field password is required!!',
'konfirmasi_password.same' => 'The password isn\'t same..',
];
}
}
And this is the RegisterController.php code:
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
use Session;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use App\Mail\MailSend;
class RegisterController extends Controller
{
public function index()
{
return view('register');
}
public function actionregister(Request $request)
{
$str = Str::random(50);
$validation = $request->validate([
'nm_lengkap' => 'required',
'tmp_lahir' => 'required',
'tgl_lahir' => 'required',
'no_hp' => 'required',
'email' => "required|email|unique:users,email",
'buat_password' => 'required|min:8',
'konfirmasi_password' => 'required|same:buat_password'
]);
if ($validation) {
$user = User::create([
'nm_lengkap' =>$request->nm_lengkap,
'tmp_lahir' => $request->tmp_lahir,
'tgl_lahir'=>$request->tgl_lahir,
'no_hp'=>$request->no_hp,
'email' => $request->email,
'password' => Hash::make($request->buat_password),
'role' => 'Santri',
'verify_key' => $str,
'active' => 0
]);
$details = [
'nm_lengkap' => $request->nm_lengkap,
'role' => $request->role,
'website' => 'www.ayongoding.com',
'datetime' => date('Y-m-d H:i:s'),
'url' => request()->getHttpHost().'/register/verify/'.$str
];
Mail::to($request->email)->send(new MailSend($details));
Session::flash('message', 'You\re registed succesfully. Please check your email to validate your account');
return redirect('register');
}
}
public function verify($verify_key)
{
$keyCheck = User::select('verify_key')
->where('verify_key', $verify_key)
->exists();
if ($keyCheck) {
$user = User::where('verify_key', $verify_key)
->update([
'active' => 1
]);
return redirect('verify_success');
}else{
return redirect('verify_failed');
}
}
/* public function verify_failed()
{
return view('verify_failed');
}
public function verify_success()
{
return view('verify_success');
} the commented functions used for web project */
}
When I try to registering in my android project, the response of api is "onFailure", not "onResponse".
And actually, I want to put the validator error to Field (Edit Text) Error of the android project, but I cant make it in onFailure... because the validator errors can't be used on onFailure...
Why that can be happen??

I do not see that you use the custom form request within your controller.
Change your RegistrationRequest class name to RegistrationRequest , cause current is LoginRequest.
And use it in your registration controller
public function actionregister(RegistrationRequest $request ...
Try this first , and hopefully you get the proper validation error response.
Salam from "below the board" ^_^

Related

erro laravel "Undefined property: Illuminate\Support\Facades\Request::$email"

I'm doing a login and registration screen, the registration screen is perfect, but the login screen is giving me a headache to authenticate.
the registration is done, but as soon as I log in it gives this error...
"Undefined property: Illuminate\Support\Facades\Request::$email"
I don't know what else to do to make it work.
CONTROLLER:
<?php
namespace App\Http\Controllers;
use App\Models\Usuario;
use Illuminate\Support\Facades\Auth;
use Request;
class Usuarios extends Controller
{
public function cadastrar()
{
$usuario = new Usuario(Request::all());
$usuario->save();
return redirect('/')->with('mensagem_sucesso', 'Cadastro efetuado com sucesso!');
}
public function index()
{
return view('layout/cadastrousuario');
}
public function indexlogin()
{
return view('layout/login');
}
public function logar(Request $request)
{
if (Auth::attempt(['email' => $request->email, 'password' => $request-> password])) {
dd('voce esta logado');
} else {
dd('voce nao esta logado');
}
}
}
MODEL:
<?php
namespace App\Models;
use App\Models\Model\Request;
use DB;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Hash;
class Usuario extends Authenticatable
{
protected $table = 'usuario';
public $timestamps = false;
protected $fillable =
array(
"codigo",
"nome",
"email",
"apelido",
"senha",
"bloqueado",
"saldo",
"saldo_atual",
"admin"
);
use HasFactory;
}
ROUTE:
<?php
use App\Http\Controllers\Lancamentos;
use App\Http\Controllers\LancamentosSimplificado;
use App\Http\Controllers\Usuarios;
use Illuminate\Support\Facades\Route;
// Route = (rota)::get ou post = (method) ( '/home' = (link) , [Lancamentos = (controller) :: class, 'logar' = ( function) ;
Route::get('/', [Lancamentos::class, 'index']);
Route::get('/salvar', [Lancamentos::class, 'salvar']);
Route::get('/maisdetalhes/{codigo}', [Lancamentos::class, 'maisdetalhes']);
Route::get('/criarchat', [Lancamentos::class, 'criarchat']);
Route::post('/cadastrar', [Lancamentos::class, 'cadastrar']);
Route::post('/cadastrar-simplificado', [LancamentosSimplificado::class, 'cadastrar']);
Route::get('/criarchat', [LancamentosSimplificado::class, 'listar']);
Route::get('/chat/{codigo}', [Lancamentos::class, 'chat']);
Route::get('/chatcriado/{codigo}', [LancamentosSimplificado::class, 'chatcriado']);
Route::get('/cadastrar-usuario', [Usuarios::class, 'index']);
Route::post('/cadastrar-usuario', [Usuarios::class, 'cadastrar']);
Route::get('/login', [Usuarios::class, 'indexlogin']);
Route::post('/login', [Usuarios::class, 'logar']);
page image as soon as I click login
to start you have to make validations in the register function to be sure that the email address arrives well and is registered. i would start by modifying this function
public function cadastrar(Request $r)
{
$r->validate([
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'min:6',
'password_confirmation' => 'required_with:password|same:password|min:6',
'custom_field' => 'custom validation'
]);
$input = $r->all();
$input['password'] = Hash::make($r->password);
$utilisateur = Model::create($input); //the Model == Usuario;
return redirect('/')->with([
'message' => "Cadastro efetuado com sucesso!",
'alert-type' => 'success',
]);
}
this is just a code snippet, I don't pretend to say that it's exactly what you need.the next way is the login function
if (Auth::attempt(['email' => $r->email, 'password' => $r->password])) {
// The user is active, not suspended, and exists.
$user = Auth::user();
if($user->fcm_token != Null){
$token = $user->createToken('AUTH')->accessToken;
$user->remember_token = $token;
$user->device_token = $user->fcm_token;
$user->save();
$response = [
"data"=> [
'user'=> $user,
'token'=> $token,
],
'message_fr' => 'Utilisateur connecté avec succès',
'message_en' => 'User logged successfully',
];
return response()->json($response, 200);
}else{
$response = [
'message_fr' => 'Vous êtes peut-être un robot',
'message_en' => 'You may be a robot',
];
return response()->json($response, 422);
}
} else {
$response = [
'message_fr' => 'Veuillez vérifier vos informations de connexion',
'message_en' => 'Please check your login information',
];
return response()->json($response, 422);
}
since you put a validation on the register, you are sure that the email is not only present, but also conforms to the nomenclature of an email
these two methods presented are examples taken from my source code of an available project, Good luck to you
You are using the wrong Request class. Request (Illuminate\Support\Facades\Request) that is aliased in config/app.php is the Facade, static proxy, for the bound Request class instance, Illuminate\Http\Request. If you want an instance of a Request you need to be using Illuminate\Http\Request.
use Illuminate\Http\Request;
Now via dependency injection you will have an instance of the Request class (which has magic methods to access inputs via dynamic properties). If you keep what you have then you would not be asking for an instance via dependency injection and would have to use the Facade as a Facade:
public function logar()
{
...
$something = Request::input(...); // static call to Facade
...
}

How to create custom validation rule for dependent input fields in laravel

In my input form, I have two fields; momentFrom & momentTo. I need to put a validation which gives error message if any of the following criteria fails.
momentFrom is greater than or equal to momentTo.
momentFrom is less than now.
My code for storing the data:
public function store(Request $request, Requisition $requisitionObj) {
$momentFrom = strtotime($request->txtTravelDate . " " . $request->txtTimeFrom);
$momentTo = strtotime($request->txtTravelDate . " " . $request->txtTimeTo);
$timeValidation = $requisitionObj->validateTiming($momentFrom, $momentTo);
if ($timeValidation['error']) {
echo 'ERROR: ' . $timeValidation['message'];
return view('requisitions.create');
} else {
/* store form data into requisition object */
$requisitionObj->travel_date = $request->txtTravelDate;
$requisitionObj->moment_from = $momentFrom;
$requisitionObj->moment_to = $momentTo;
$requisitionObj->save();
return redirect()->route('requisitions.index');
}
}
I have seen laravel custom validation rules where only one field can be validated at a time. But in my scenario I need to check both fields at a time depending on each other. How can I achieve this?
Thanks for any help in advance!
Creating new Rule Class
You can create your custom rule with the artisan command: php artisan make:rule YourRuleNamethis will create a new Rule Class file into the Rules folder.
By default the created file contains a constructor, a passes method and a message method.
Rules Logic
If you have some complicated rules where you need the request or some models, you can pass them via the constructor.
public function __construct(Request $request, User $user, ....)
{
//save them into class variables to access them later
$this->request = $request;
$this->user = $user;
}
Otherwise you can directly put your validation logic into the passes method:
public function passes($attribute, $value){
//some code
return #myCondition
}
Last you are able to specify the message if the validation fails.
public function message()
{
return 'Your message';
}
To use your rule simply add it to your rules array:
$rules = [
'my_attribute' => [new MyCustomRule(),...],
]
At last, I have solved this problem using FormRequest and AppServiceProvider. Thought this would help others who come to this place.
First I have created FormRequest validator using following artisan command.
php artisan make:request StoreRequisition
Then added primary validation rules and messages into it.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreRequisition extends FormRequest {
public function authorize() {
return true;
}
public function rules() {
$rules = [
'txtTravelDate' => 'required|date_format:Y-m-d|after_or_equal:today',
'txtTimeFrom' => 'required|date_format:H:i|travel_time_validate',
'txtTimeTo' => 'required|date_format:H:i',
];
return $rules;
}
public function messages() {
return [
'txtTravelDate.required' => 'Travel date is required!',
'txtTravelDate.date_format' => 'Invalid format for Travel Date!',
'txtTravelDate.after_or_equal' => 'Travel Date should be today or later!',
'txtTimeFrom.required' => 'Time From is required!',
'txtTimeFrom.date_format' => 'Invalid format for Time From!',
'txtTimeFrom.travel_time_validate' => 'Invalid time selected!',
'txtTimeTo.required' => 'Time To is required!',
'txtTimeTo.date_format' => 'Invalid format for Time To!',
'listFunction.required' => 'Department to be selected!',
'txtPickLoc.required' => 'Pickup Location is required!',
'txtDropLoc.required' => 'Drop Location is required!',
'listPurpose.required' => 'Travel Purpose to be selected!'
];
}
}
Then inside app\Providers\AppServiceProvider, added the extra validation logic.
public function boot() {
Validator::extend(
'travel_time_validate',
function ($attribute, $value, $parameters, $validator) {
$inputs = $validator->getData();
/* convert time to moments */
$momentFrom = strtotime($inputs['txtTravelDate'] . " " . $inputs['txtTimeFrom']);
$momentTo = strtotime($inputs['txtTravelDate'] . " " . $inputs['txtTimeTo']);
$result = true;
if ($momentFrom >= $momentTo) {
$result = false;
}
return $result;
}
);
}
My Controller:
public function store(StoreRequisition $request, Requisition $requisitionObj) {
$validatedData = $request->validated();
/* store form data into requisition object */
$requisitionObj->requester_id = Auth::user()->id;
$requisitionObj->travel_date = $request->txtTravelDate;
$requisitionObj->time_from = $request->txtTimeFrom;
$requisitionObj->time_to = $request->txtTimeTo;
$requisitionObj->purpose_id = $request->listPurpose;
/* Finally save the record into the database */
$requisitionObj->save();
return redirect()->route('requisitions.index');
}
Example how make custom rule for validation in Laravel 8.x / Lumen 8.x.
public static function rules(){
return [
'number' => [
'required', 'min:1', 'max:30', 'string', self::testNumber(),
],
];
}
public static function testNumber(){
return function($attribute, $value, $fail){
if ($value === 'foo'){
$fail('The '.$attribute.' is invalid.');
}
};
}

Can i ignore unique value when update record laravel 5.8? [duplicate]

I have a Laravel User model which has a unique validation rule on username and email. In my Repository, when I update the model, I revalidate the fields, so as to not have a problem with required rule validation:
public function update($id, $data) {
$user = $this->findById($id);
$user->fill($data);
$this->validate($user->toArray());
$user->save();
return $user;
}
This fails in testing with:
ValidationException: {"username":["The username has already been
taken."],"email":["The email has already been taken."]}
Is there a way of fixing this elegantly?
Append the id of the instance currently being updated to the validator.
Pass the id of your instance to ignore the unique validator.
In the validator, use a parameter to detect if you are updating or creating the resource.
If updating, force the unique rule to ignore a given id:
//rules
'email' => 'unique:users,email_address,' . $userId,
If creating, proceed as usual:
//rules
'email' => 'unique:users,email_address',
Another elegant way...
In your model, create a static function:
public static function rules ($id=0, $merge=[]) {
return array_merge(
[
'username' => 'required|min:3|max:12|unique:users,username' . ($id ? ",$id" : ''),
'email' => 'required|email|unique:member'. ($id ? ",id,$id" : ''),
'firstname' => 'required|min:2',
'lastname' => 'required|min:2',
...
],
$merge);
}
Validation on create:
$validator = Validator::make($input, User::rules());
Validation on update:
$validator = Validator::make($input, User::rules($id));
Validation on update, with some additional rules:
$extend_rules = [
'password' => 'required|min:6|same:password_again',
'password_again' => 'required'
];
$validator = Validator::make($input, User::rules($id, $extend_rules));
Nice.
Working within my question:
public function update($id, $data) {
$user = $this->findById($id);
$user->fill($data);
$this->validate($user->toArray(), $id);
$user->save();
return $user;
}
public function validate($data, $id=null) {
$rules = User::$rules;
if ($id !== null) {
$rules['username'] .= ",$id";
$rules['email'] .= ",$id";
}
$validation = Validator::make($data, $rules);
if ($validation->fails()) {
throw new ValidationException($validation);
}
return true;
}
is what I did, based on the accepted answer above.
EDIT: With Form Requests, everything is made simpler:
<?php namespace App\Http\Requests;
class UpdateUserRequest extends Request
{
/**
* 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 [
'name' => 'required|unique:users,username,'.$this->id,
'email' => 'required|unique:users,email,'.$this->id,
];
}
}
You just need to pass the UpdateUserRequest to your update method, and be sure to POST the model id.
Unique Validation With Different Column ID In Laravel
'UserEmail'=>"required|email|unique:users,UserEmail,$userID,UserID"
or what you could do in your Form Request is (for Laravel 5.3+)
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'. $this->user
//here user is users/{user} from resource's route url
];
}
i've done it in Laravel 5.6 and it worked.
'email' => [
'required',
Rule::exists('staff')->where(function ($query) {
$query->where('account_id', 1);
}),
],
'email' => [
'required',
Rule::unique('users')->ignore($user->id)->where(function ($query) {
$query->where('account_id', 1);
})
],
Laravel 5 compatible and generic way:
I just had the same problem and solved it in a generic way. If you create an item it uses the default rules, if you update an item it will check your rules for :unique and insert an exclude automatically (if needed).
Create a BaseModel class and let all your models inherit from it:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model {
/**
* The validation rules for this model
*
* #var array
*/
protected static $rules = [];
/**
* Return model validation rules
*
* #return array
*/
public static function getRules() {
return static::$rules;
}
/**
* Return model validation rules for an update
* Add exception to :unique validations where necessary
* That means: enforce unique if a unique field changed.
* But relax unique if a unique field did not change
*
* #return array;
*/
public function getUpdateRules() {
$updateRules = [];
foreach(self::getRules() as $field => $rule) {
$newRule = [];
// Split rule up into parts
$ruleParts = explode('|',$rule);
// Check each part for unique
foreach($ruleParts as $part) {
if(strpos($part,'unique:') === 0) {
// Check if field was unchanged
if ( ! $this->isDirty($field)) {
// Field did not change, make exception for this model
$part = $part . ',' . $field . ',' . $this->getAttribute($field) . ',' . $field;
}
}
// All other go directly back to the newRule Array
$newRule[] = $part;
}
// Add newRule to updateRules
$updateRules[$field] = join('|', $newRule);
}
return $updateRules;
}
}
You now define your rules in your model like you are used to:
protected static $rules = [
'name' => 'required|alpha|unique:roles',
'displayName' => 'required|alpha_dash',
'permissions' => 'array',
];
And validate them in your Controller. If the model does not validate, it will automatically redirect back to the form with the corresponding validation errors. If no validation errors occurred it will continue to execute the code after it.
public function postCreate(Request $request)
{
// Validate
$this->validate($request, Role::getRules());
// Validation successful -> create role
Role::create($request->all());
return redirect()->route('admin.role.index');
}
public function postEdit(Request $request, Role $role)
{
// Validate
$this->validate($request, $role->getUpdateRules());
// Validation successful -> update role
$role->update($request->input());
return redirect()->route('admin.role.index');
}
That's it! :) Note that on creation we call Role::getRules() and on edit we call $role->getUpdateRules().
I have BaseModel class, so I needed something more generic.
//app/BaseModel.php
public function rules()
{
return $rules = [];
}
public function isValid($id = '')
{
$validation = Validator::make($this->attributes, $this->rules($id));
if($validation->passes()) return true;
$this->errors = $validation->messages();
return false;
}
In user class let's suppose I need only email and name to be validated:
//app/User.php
//User extends BaseModel
public function rules($id = '')
{
$rules = [
'name' => 'required|min:3',
'email' => 'required|email|unique:users,email',
'password' => 'required|alpha_num|between:6,12',
'password_confirmation' => 'same:password|required|alpha_num|between:6,12',
];
if(!empty($id))
{
$rules['email'].= ",$id";
unset($rules['password']);
unset($rules['password_confirmation']);
}
return $rules;
}
I tested this with phpunit and works fine.
//tests/models/UserTest.php
public function testUpdateExistingUser()
{
$user = User::find(1);
$result = $user->id;
$this->assertEquals(true, $result);
$user->name = 'test update';
$user->email = 'ddd#test.si';
$user->save();
$this->assertTrue($user->isValid($user->id), 'Expected to pass');
}
I hope will help someone, even if for getting a better idea. Thanks for sharing yours as well.
(tested on Laravel 5.0)
A simple example for roles update
// model/User.php
class User extends Eloquent
{
public static function rolesUpdate($id)
{
return array(
'username' => 'required|alpha_dash|unique:users,username,' . $id,
'email' => 'required|email|unique:users,email,'. $id,
'password' => 'between:4,11',
);
}
}
.
// controllers/UsersControllers.php
class UsersController extends Controller
{
public function update($id)
{
$user = User::find($id);
$validation = Validator::make($input, User::rolesUpdate($user->id));
if ($validation->passes())
{
$user->update($input);
return Redirect::route('admin.user.show', $id);
}
return Redirect::route('admin.user.edit', $id)->withInput()->withErrors($validation);
}
}
If you have another column which is being used as foreign key or index then you have to specify that as well in the rule like this.
'phone' => [
"required",
"phone",
Rule::unique('shops')->ignore($shopId, 'id')->where(function ($query) {
$query->where('user_id', Auth::id());
}),
],
I am calling different validation classes for Store and Update. In my case I don't want to update every fields, so I have baseRules for common fields for Create and Edit. Add extra validation classes for each. I hope my example is helpful. I am using Laravel 4.
Model:
public static $baseRules = array(
'first_name' => 'required',
'last_name' => 'required',
'description' => 'required',
'description2' => 'required',
'phone' => 'required | numeric',
'video_link' => 'required | url',
'video_title' => 'required | max:87',
'video_description' => 'required',
'sex' => 'in:M,F,B',
'title' => 'required'
);
public static function validate($data)
{
$createRule = static::$baseRules;
$createRule['email'] = 'required | email | unique:musicians';
$createRule['band'] = 'required | unique:musicians';
$createRule['style'] = 'required';
$createRule['instrument'] = 'required';
$createRule['myFile'] = 'required | image';
return Validator::make($data, $createRule);
}
public static function validateUpdate($data, $id)
{
$updateRule = static::$baseRules;
$updateRule['email'] = 'required | email | unique:musicians,email,' . $id;
$updateRule['band'] = 'required | unique:musicians,band,' . $id;
return Validator::make($data, $updateRule);
}
Controller:
Store method:
public function store()
{
$myInput = Input::all();
$validation = Musician::validate($myInput);
if($validation->fails())
{
$key = "errorMusician";
return Redirect::to('musician/create')
->withErrors($validation, 'musicain')
->withInput();
}
}
Update method:
public function update($id)
{
$myInput = Input::all();
$validation = Musician::validateUpdate($myInput, $id);
if($validation->fails())
{
$key = "error";
$message = $validation->messages();
return Redirect::to('musician/' . $id)
->withErrors($validation, 'musicain')
->withInput();
}
}
public static function custom_validation()
{
$rules = array('title' => 'required ','description' => 'required','status' => 'required',);
$messages = array('title.required' => 'The Title must be required','status.required' => 'The Status must be required','description.required' => 'The Description must be required',);
$validation = Validator::make(Input::all(), $rules, $messages);
return $validation;
}
I had the same problem.
What I've done: add in my view hidden field with id of a model and in validator check the unique, only if I've get some id from view.
$this->validate(
$request,
[
'index' => implode('|', ['required', $request->input('id') ? '' : 'unique:members']),
'name' => 'required',
'surname' => 'required',
]
);
You can trying code bellow
return [
'email' => 'required|email|max:255|unique:users,email,' .$this->get('id'),
'username' => 'required|alpha_dash|max:50|unique:users,username,'.$this->get('id'),
'password' => 'required|min:6',
'confirm-password' => 'required|same:password',
];
Laravel 5.8 simple and easy
you can do this all in a form request with quite nicely. . .
first make a field by which you can pass the id (invisible) in the normal edit form. i.e.,
<div class="form-group d-none">
<input class="form-control" name="id" type="text" value="{{ $example->id }}" >
</div>
...
Then be sure to add the Rule class to your form request like so:
use Illuminate\Validation\Rule;
... Add the Unique rule ignoring the current id like so:
public function rules()
{
return [
'example_field_1' => ['required', Rule::unique('example_table')->ignore($this->id)],
'example_field_2' => 'required',
];
... Finally type hint the form request in the update method the same as you would the store method, like so:
public function update(ExampleValidation $request, Examle $example)
{
$example->example_field_1 = $request->example_field_1;
...
$example->save();
$message = "The aircraft was successully updated";
return back()->with('status', $message);
}
This way you won't repeat code unnecessarily :-)
public function rules()
{
if ($this->method() == 'PUT') {
$post_id = $this->segment(3);
$rules = [
'post_title' => 'required|unique:posts,post_title,' . $post_id
];
} else {
$rules = [
'post_title' => 'required|unique:posts,post_title'
];
}
return $rules;
}
For a custom FormRequest and Laravel 5.7+ you can get the id of your updated model like this:
public function rules()
{
return [
'name' => 'required|min:5|max:255|unique:schools,name,'.\Request::instance()->id
];
}
For anyone using a Form request
In my case i tried all of the following none of them worked:
$this->id, $this->user->id, $this->user.
It was because i could not access the model $id nor the $id directly.
So i got the $id from a query using the same unique field i am trying to validate:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$id = YourModel::where('unique_field',$this->request->get('unique_field'))->value('id');
return [
'unique_field' => ['rule1','rule2',Rule::unique('yourTable')->ignore($id)],
];
}
It will work 100%
I have both case implement like One case is same form field in database table products and other is products_name is form field and in table, it's name is name, how we can validate and ignore that id while updating. I have encrypted that so i'm decrypted id, if you are encrypt then you will decrypt otherwise pass it as it's coming from the form.
$request->validate([
'product_code' => 'required|unique:products,product_code,'.decrypt($request->hiddenProductId),
'products_name' => 'required|unique:products,name,'.decrypt($request->hiddenProductId),
]);
there is detailed and straightforward answer to this question, I was looking for too
https://laravel.com/docs/9.x/validation#rule-unique

return first error in customized formatted in laravel 5.5 form requests

Before laravel 5.5 I used a form request like this with a customized format :
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
class StoreProductRequest extends FormRequest
{
public function authorize ()
{
return true;
}
public function rules ()
{
return [
'title' => 'required',
'desc' => 'required',
];
}
public function response (array $errors)
{
return response()->json($errors, 200);
}
protected function formatErrors (Validator $validator)
{
$result = ['success' => false, 'msg' => $validator->errors()->first()];
return $result;
}
}
Means when an error occured, only the first error returned as a json format like this :
{
"success" : "false",
"msg" : "title field is required "
}
But seem that in laravel 5.5 in this way could not format error like this.
Now I want to return error exactly same format I mentioned above in json format but I do not know How can
This functionality was changed in Laravel 5.5. From the upgrade guide "A Note On Form Requests":
If you were customizing the response format of an individual form request, you should now override the failedValidation method of that form request, and throw an HttpResponseException instance containing your custom response
Your updated Form Request might look something like this (pseudo-code, not tested):
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
class StoreProductRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'desc' => 'required',
];
}
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(
response()->json(['success' => false, 'msg' => $validator->errors()->first()], 400)
);
}
}
protected function formatErrors (Validator $validator)
{
$result = ['success' => false, 'msg' => $validator->errors()];
return $result;
}
Expanding on #Aken Roberts answer. Since this is an error response for a form, I use the error key (input field name) to display the error beside the input.
You can get the first error key from the keys method. With Laravel 5.7 this works as expected:
public function failedValidation(Validator $validator)
{
throw new HttpResponseException(
response()->json([
'success' => false,
'error' => (object) [
$validator->errors()->keys()[0] => $validator->errors()->first()
]
], 400)
);
}

How to change the default message in Respect Validation?

I use Respect Validation for password matches on a Slim app:
class PasswordController extends Controller
{
;
;
public function postChangePassword($request, $response) {
$validation = $this->validator->validate($request, [
'password_old' => v::noWhitespace()->notEmpty()->matchesPassword($this->auth->user()->password),
'password' => v::noWhitespace()->notEmpty()
]);
if($validation->failed()) {
// stay on the same page
}
die('update password');
}
}
I can authenticate the password:
class MatchesPassword extends AbstractRule
{
protected $password;
public function __construct($password) {
$this->password = $password;
}
public function validate($input) {
// compare the non-hashed input with the already hashed password
}
}
...and I created my own custom string for the 3rd rule ('password_old'):
class MatchesPasswordException extends ValidationException
{
public static $defaultTemplates = [
self::MODE_DEFAULT => [
self::STANDARD => 'Password does not match.',
],
];
}
The script works fine, I get the following message when I submit with 'password_old' field empty:
"Password_old must not be empty"
I would like to change the above default message to a custom string, e.g.:
"The value must not be empty"
You can overwrite the messages using the findMessages method of ValidationException and using assert:
try {
v::noWhitespace()->notEmpty()->matchesPassword($this->auth->user()->password)->assert($request->getParam('password_old'));
v::noWhitespace()->notEmpty()->assert($request->getParam('password'));
} catch (ValidationException $exception) {
$errors = $exception->findMessages([
'notEmpty' => 'The value must not be empty'
]);
print_r($errors);
}

Categories