英文:
Laravel does not validate input data before insertion
问题
I encountered an error when the user registers, everything is ok and works perfectly, but when the user registers again with the same previous data, it shows this error:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '123456789' for key 'users.users_phone_unique'
and i have no ideo what is wrong in these codes
i'm using laravel 10
this is my register controller
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'min:10'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'phone' => ['required', 'string', 'max:11'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'phone' => $data['phone'],
'password' => Hash::make($data['password']),
]);
}
}
this is my user.php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
'phone',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'phone',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
this is my create user table migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('password');
$table->string('phone')->unique();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
}
};
英文:
I encountered an error when the user registers, everything is ok and works perfectly, but when the user registers again with the same previous data, it shows this error:
> SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '123456789' for key 'users.users_phone_unique'
and i have no ideo what is wrong in these codes
i'm using laravel 10
this is my register controller
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'min:10'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
'phone' => ['required', 'string', 'max:11'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'phone' => $data['phone'],
'password' => Hash::make($data['password']),
]);
}
}
this is my user.php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
'phone',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'phone',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
this is my create user table migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('password');
$table->string('phone')->unique();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
}
};
答案1
得分: 0
在你的控制器中,你没有验证电话号码的唯一性,因此数据会“传递到”数据库级别,然后由于违反了“unique”约束而失败。
你应该在你的RegisterController
中添加一个unique
验证规则,以便在表单发送后立即失败。
例如:
'phone' => ['required', 'string', 'max:11','unique:users']
英文:
In your controller you're not validating the uniqueness of the phone number, hence the data is "passed down" to the DB level, and then it fails because of the violated unique
constraint.
You should add a unique
validation rule in your RegisterController
in order to fail as soon as the form is sent.
For example:
'phone' => ['required', 'string', 'max:11','unique:users']
答案2
得分: 0
我建议采用另一种被认为是更好的验证实践的方法。
- 运行
php artisan make:request CreateUserRequest
,将在/app/Http/Requests
目录下创建CreateUserRequest
文件。 - 根据你的需求编辑该文件,例如:
/**
* 获取适用于请求的验证规则。
*
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'min:10'],
'phone' => ['required', 'string', 'max:11','unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
/**
* 或者如果你想接受复杂的密码,可以在`CreateUserRequest`的顶部添加`use Illuminate\Validation\Rules\Password;`,
* 然后使用以下规则
*/
'password' => [
'required', 'confirmed',
Password::min(8)->letters()->mixedCase()->numbers()->symbols()
],
];
}
- 如果需要在验证失败时添加自定义消息,你可以在
CreateUserRequest
类中添加以下方法:
/**
* 为验证失败设置适当的错误消息
*
* @return array<string>
*/
public function messages() {
return [
'password.required' => '我友好的提示消息给用户',
];
}
你需要相应地修改你的控制器,更多信息请参考表单验证文档。
英文:
I'm gonna suggest a different approach which is considered to be a better practice for validation.
- run
php artisan make:request CreateUserRequest
, theCreateUserRequest
file will be created in/app/Http/Requests
directory. - edit the file according to your needs, for example:
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'min:10'],
'phone' => ['required', 'string', 'max:11','unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
/**
* or if you want to accept complex passwords add `use Illuminate\Validation\Rules\Password;`
* on top of the `CreateUserRequest` and then use the following rule instead
*/
'password' => [
'required', 'confirmed',
Password::min(8)->letters()->mixedCase()->numbers()->symbols()
],
];
}
- for a custom message in case of a failed validation you can add the following method to your
CreateUserRequest
class:
/**
* Set proper error messages for failed validations
*
* @return array<string>
*/
public function messages() {
return [
'password.required' => 'my friendly message to the user',
];
}
You need to modify your controller accordingly, for more information take a look at Form Validation Docs.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论