如何验证记录更新中的唯一字段

How to validate a unique field on a record update

我最近启动了一个 laravel 项目来控制一些活动,但我目前在验证方面遇到问题,特别是在更新包含唯一值 table 的特定记录时 [=19] =]

上个月 laravel 8 启动后的几天,我开始了这个项目,所以可能有些变化影响了我。

这些是我的迁移

第一个是用户及其数据, ...

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB; //para hacer insersion

class CrearTablaUsuarios extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('usuarios', function (Blueprint $table) 
        {
            $table->increments('id_usuario');
            $table->unique('id_usuario');
            $table->string('nombre_usuario',255);
            $table->string('apellido_usuario',255);
            $table->string('foto_usuario', 255);
            $table->string('alias',255);
            $table->unique('alias');
            $table->string('contraseña',255);
            $table->text('respuesta_pregunta');
            $table->string('telefono_usuario',255);
            $table->unique('telefono_usuario');
            $table->text('correo');
            $table->unique('correo');
            $table->integer('id_tipo_usuario')->unsigned();
            $table->foreign('id_tipo_usuario')->references('id_tipo_usuario')->on('tipos_usuarios')->onDelete('cascade');
            $table->integer('id_cargo_usuario')->unsigned();
            $table->foreign('id_cargo_usuario')->references('id_cargo_usuario')->on('cargos_usuarios')->onDelete('cascade');
            $table->boolean('estado_usuario');
            $table->date('fecha_registro');
            $table->date('fecha_retiro')->nullable();
        });

       
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {

        Schema::dropIfExists('usuarios');
    }
}

...

其次是描述用户类型的table ...

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB; //para hacer insersion

class CrearTablaTiposUsuarios extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tipos_usuarios', function (Blueprint $table) {
            $table->increments('id_tipo_usuario');
            $table->unique('id_tipo_usuario');
            $table->string('nombre_tipo_usuario', 255);
            $table->unique('nombre_tipo_usuario');
            $table->text('descripcion_tipo_usuario');
        });

           // Insert some stuff
        DB::table('tipos_usuarios')
                ->insert(
                [ 
                    [
                        'nombre_tipo_usuario' => 'Administrador',
                        'descripcion_tipo_usuario' => 'Este tipo de usuario se encarga de manejar la aplicación y tiene control total, ademas de ser el unico que puede crear usuarios'
                    ],
                    [
                        'nombre_tipo_usuario' => 'Supervisor',
                        'descripcion_tipo_usuario' => 'Se encarga de ver las actividades de los usuarios , ademas puede agregar clientes y puede asignar clientes a usuarios'
                    ],
                    [
                        'nombre_tipo_usuario' => 'Publicador',
                        'descripcion_tipo_usuario' => 'Este tipo de usuario solo puede agregar conteos a las publiaciones de los clientes'
                    ]
                ]);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('usuarios');
        Schema::dropIfExists('tipos_usuarios');
    }
}

... 一个 table 来描述用户位置 ...

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB; //para hacer insersion

class CrearTablaCargosUsuarios extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('cargos_usuarios', function (Blueprint $table) {
            $table->increments('id_cargo_usuario');
            $table->unique('id_cargo_usuario');
            $table->string('nombre_cargo', 255);
            $table->unique('nombre_cargo');
            $table->text('descripcion_cargo');
        });

        // Insert some stuff
        DB::table('cargos_usuarios')
                   ->insert(
        [ 
            [
                'nombre_cargo' => 'Gerente',
                'descripcion_cargo' => 'Es el encargado de manejar la empresa de y todas las labores ejecutivas'
            ],
            [
                'nombre_cargo' => 'Programador',
                'descripcion_cargo' => 'Se encarga de dar soporte tecnico, desarrolla sitios web y aplicaciones.'
            ],
            [
                'nombre_cargo' => 'Diseñador',
                'descripcion_cargo' => 'Realiza diversos trabajos como diseño de post, logos y otros.'
            ]
        ]);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('cargos_usuarios');
    }
}
...

This last tables must be migrate before "usuarios" to about issues

This is my model

...
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class usuarios extends Model
{
    use HasFactory;
    public $timestamps = false; //Esto es necesario para que no se produzcan errores de insersción ya que laravel los usa por predeterminado
    
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'usuarios';
    
    /**
     * The primary key associated with the table.
     *
     * @var string
     */
    protected $primaryKey = 'id_usuario';


    public function obtener_tipo_usuario()
    {
        return $this->hasOne('App\Models\tipos_usuarios', 'id_tipo_usuario', 'id_tipo_usuario');
    }


    public function obtener_cargo_usuario()
    {
        return $this->hasOne('App\Models\cargos_usuarios', 'id_cargo_usuario', 'id_cargo_usuario');
    }

    public function suspender_usuario()
    {
        if ($this->estado_usuario == false) 
        {
            return 'Este usuario ya ha sido suspendido';
        }
        else 
        {
            $this->estado_usuario = false;
            $this->fecha_retiro = date("Y-m-d");
            $this->save();
            return 'usuario suspendido';    
        }
    }

    public function activar_usuario()
    {
        if ($this->estado_usuario == true) 
        {
            return 'Este usuario ya esta activo';
        }
        else 
        {
            $this->estado_usuario = true;
            $this->fecha_retiro = null;
            $this->save();
            return 'Usuario dado de alta';
        }

    }

}

...

这是我的ususarios控制器

...

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\usuarios;
use DB; 
use Illuminate\Support\Facades\Storage; //para almacenar
use Illuminate\Http\File;
use Illuminate\Validation\Rule;

class UsuariosController extends Controller
{

    /**
     * Muestra el formulario para agregar usuarios
     * Este debe estar disponible solo para el administrador
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        $tipos_usuarios = DB::table('tipos_usuarios')->where('nombre_tipo_usuario', '!=' ,'Administrador')->get();
        $cargos_usuarios = DB::table('cargos_usuarios')->get();
        return view('layouts/sistema/usuarios/agregar_usuario', ['tipos_usuarios' => $tipos_usuarios, 'cargos_usuarios' => $cargos_usuarios] );
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $solicitud
     * @return \Illuminate\Http\Response
     */
    public function store(Request $solicitud)
    {

        $solicitud->validate([
            'archivo_foto_usuario' =>['required', 'mimes:jpeg,png, webp,jpg', 'dimensions:min_width=50,min_height=50,max_width=200,min_height=200'],

            'nombre_usuario' => ['required', 'min:3', 'max:255'],
            'apellido_usuario' =>  ['required', 'min:3', 'max:255'],

            'telefono_usuario' => ['required', 'regex:/^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$/','unique:usuarios,telefono_usuario' ],
    

            'alias_usuario' =>  ['required', 'min:3', 'max:255','unique:usuarios,alias'],

            'contraseña_usuario' =>  ['required','min:8','regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$/'],

            'correo_usuario' => ['required', 'regex:/[a-z0-9._%+-]@manilastudio.com$/', 'unique:usuarios,correo'], 

            'tipo_usuario' => 'required',
            'cargo_usuario' => 'required',
        ],  [
            'archivo_foto_usuario.required' => 'Se necesita una imagen en formato compatible',
            'archivo_foto_usuario.mimes' => 'Formato de imagen no soportado',
            'archivo_foto_usuario.dimensions' => 'La imagen debe ser de mimino 50x50 y maximo 200x200',

            'nombre_usuario.required' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'nombre_usuario.min' => 'Campo requerido, introduzca al menos 4 caracteres.',

            'apellido_usuario.required' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'apellido_usuario.min' => 'Campo requerido, introduzca al menos 4 caracteres.',

            'telefono_usuario.required' => 'Introduza un numero teléfonico valido',
            'telefono_usuario.regex' => 'El formato debe ser +50512345678',
            'telefono_usuario.unique' => 'Este número ya esta en uso',

            'alias_usuario.required' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'alias_usuario.min' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'alias_usuario.unique' => 'Esta alias ya esta en uso',

            'contraseña_usuario.required' => 'Campo requerido, introduzca al menos 8 letras, con números o caracteres',
            'contraseña_usuario.min' => 'Campo requerido, introduzca al menos 8 letras, con números o caracteres.',
            'contraseña_usuario.regex' => 'La contraseña temporal debe tener letras o números y caracteres',

            'correo_usuario.regex' => 'El correo debe usar el dominio manilastudio.com',
            'correo_usuario.required' => 'Se necesita asignar un correo electronico',
            'correo_usuario.unique' => 'Este correo ya esta en uso'
        ]);

        $nuevo_usuario = new usuarios();

        $nuevo_usuario->nombre_usuario = $solicitud->input('nombre_usuario');
        $nuevo_usuario->apellido_usuario = $solicitud->input('apellido_usuario');

       /**Guardar en un directorio */
        if ($solicitud->hasFile('archivo_foto_usuario')) 
        {
            $nuevo_usuario->foto_usuario  = $solicitud->archivo_foto_usuario->store('img/usuarios', 'public');
            $solicitud->file('archivo_foto_usuario')->store( 'img/usuarios/');
        }
        else
        {
            $nuevo_usuario->foto_usuario = 'img/usarios/user.png';
        }

        
        $nuevo_usuario->alias = $solicitud->input('alias_usuario');
        $nuevo_usuario->contraseña = $solicitud->input('contraseña_usuario');
        $nuevo_usuario->telefono_usuario = $solicitud->input('telefono_usuario');
        $nuevo_usuario->correo = $solicitud->input('correo_usuario');
        $nuevo_usuario->id_tipo_usuario = $solicitud->input('tipo_usuario');
        $nuevo_usuario->id_cargo_usuario = $solicitud->input('cargo_usuario');
        $nuevo_usuario->fecha_registro = date("Y-m-d");
        $nuevo_usuario->fecha_retiro = null;
        $nuevo_usuario->respuesta_pregunta = 'hola';
        $nuevo_usuario->estado_usuario = true;
        $nuevo_usuario->save();

        return redirect('/usuarios');


    }


    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\usuarios $id_usuario
     * @return \Illuminate\Http\Response
     */
    public function edit(usuarios $usuario)
    {
      //  $usuario = usuarios::find($usuario);
        $tipos_usuarios = DB::table('tipos_usuarios')->where('nombre_tipo_usuario', '!=' ,'Administrador')->get();
        $cargos_usuarios = DB::table('cargos_usuarios')->get();
      
       return view('layouts/sistema/usuarios/editar_usuario', ['usuario' => $usuario, 'tipos_usuarios' => $tipos_usuarios, 'cargos_usuarios' => $cargos_usuarios]);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\usuarios $user
     * @return \Illuminate\Http\Response
     */
    public function update(Request $solicitud, usuarios $usuario)
    {   
       // $usuario = usuarios::findOrFail($id_usuario);
       // dd($usuario->id_usuario);
       $valido =  $solicitud->validate([
            'estado_usuario' =>['required'],
            'archivo_foto_usuario' =>['required', 'mimes:jpeg,png, webp,jpg', 'dimensions:min_width=50,min_height=50,max_width=200,min_height=200'],

            'nombre_usuario' => ['required', 'min:3', 'max:255'],
            'apellido_usuario' =>  ['required', 'min:3', 'max:255'],

            'telefono_usuario' => ['required', 'regex:/^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$/', Rule::unique('usuarios')->ignore($usuario) ],
 

            'alias_usuario' =>  ['required','min:3','max:255',Rule::unique('usuarios')->ignore($usuario)], 

            'contraseña_usuario' =>  ['required','min:8','regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$/', Rule::unique('usuarios')->ignore($usuario)],

            'correo_usuario' => ['required', 'regex:/[a-z0-9._%+-]@manilastudio.com$/', /*'unique:usuarios,correo'*/ Rule::unique('usuarios')->ignore($usuario)], 

            'tipo_usuario' => 'required',
            'cargo_usuario' => 'required',
        ],  
        [
            'estado_usuario.required' => "Debe fijarse un estado para este usuario",

           'archivo_foto_usuario.required' => 'Se necesita una imagen en formato compatible',
            'archivo_foto_usuario.mimes' => 'Formato de imagen no soportado',
            'archivo_foto_usuario.dimensions' => 'La imagen debe ser de mimino 50x50 y maximo 200x200',

            'nombre_usuario.required' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'nombre_usuario.min' => 'Campo requerido, introduzca al menos 4 caracteres.',

            'apellido_usuario.required' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'apellido_usuario.min' => 'Campo requerido, introduzca al menos 4 caracteres.',

            'telefono_usuario.required' => 'Introduza un numero teléfonico valido',
            'telefono_usuario.regex' => 'El formato debe ser +50512345678',
            'telefono_usuario.unique' => 'Este número ya esta en uso',

            'alias_usuario.required' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'alias_usuario.min' => 'Campo requerido, introduzca al menos 4 caracteres.',
            'alias_usuario.unique' => 'Esta alias ya esta en uso',

            'contraseña_usuario.required' => 'Campo requerido, introduzca al menos 8 letras, con números o caracteres',
            'contraseña_usuario.min' => 'Campo requerido, introduzca al menos 8 letras, con números o caracteres.',
            'contraseña_usuario.regex' => 'La contraseña temporal debe tener letras o números y caracteres',

            'correo_usuario.regex' => 'El correo debe usar el dominio manilastudio.com',
            'correo_usuario.required' => 'Se necesita asignar un correo electronico',
            'correo_usuario.unique' => 'Este correo ya esta en uso'
        ]);

        $usuario->nombre_usuario = $solicitud->input('nombre_usuario');
        $usuario->apellido_usuario = $solicitud->input('apellido_usuario');

       /**Guardar en un directorio */
        if ($solicitud->hasFile('archivo_foto_usuario')) 
        {
            Storage::disk('public')->delete($usuario->foto_usuario);
            $usuario->foto_usuario  = $solicitud->archivo_foto_usuario->store('img/usuarios', 'public');
            $solicitud->file('archivo_foto_usuario')->store( 'img/usuarios/');
        }
        else
        {
            $usuario->foto_usuario = 'img/usarios/user.png';
        }

       // dd($solicitud->hasFile('archivo_foto_usuario'));
        
        $usuario->alias = $solicitud->input('alias_usuario');
        $usuario->contraseña = $solicitud->input('contraseña_usuario');
        $usuario->telefono_usuario = $solicitud->input('telefono_usuario');
        $usuario->correo = $solicitud->input('correo_usuario');
        $usuario->id_tipo_usuario = $solicitud->input('tipo_usuario');
        $usuario->id_cargo_usuario = $solicitud->input('cargo_usuario');
        $usuario->fecha_registro = date("Y-m-d");

        if ($solicitud->estado_usuario == 0) 
        {
            $usuario->fecha_retiro = date("Y-m-d");
        }
        
        $usuario->respuesta_pregunta = 'hola';
        $usuario->estado_usuario = $solicitud->estado_usuario;

        $usuario->save();


    
        return redirect('/usuarios');
    }
}
...

and this is my view 

...
@section('titulo', 'Modificar datos de Usuario')
<x-master>
<div class="container-fluid mt-5">
    <div class="text-left">
        <h1 class="font-weight-bolder"> 
            Modificar Datos de Usuario
        </h1>
    </div>
    <div class="mt-5">
    <form id="formulario-agregar-usuario" class="form" method="POST" action="/usuarios/{{ $usuario->id_usuario }}" enctype="multipart/form-data">
            @csrf
            @method('PUT')
            <div class="row">
                <div class="col-sm-2">
                    <div class="border rounded p-2 bg-white">
                        <div class="border rounded">
                        <img class="border rounded-circle w-100 img-fluid mr-3" src="/storage/{{$usuario->foto_usuario}}" alt="" title="Nombre Usuario"> 
                        </div>
                    </div>
                    <br>
                    <input class="btn" type="file" name="archivo_foto_usuario">
                    @error('archivo_foto_usuario') <div class="validacion" >{{ $errors->first('archivo_foto_usuario')}}</div> @enderror
                    <div class="mt-4">
                        <input type="radio" name="estado_usuario" id="activo" value="1" @if ($usuario->estado_usuario == 1 ) checked="checked" @endif>
                        <label for="activo" class="font-weight-bolder text-uppercase text-success" >Activo</label><br>
                        <input type="radio" name="estado_usuario" id="suspender" value="0" @if ($usuario->estado_usuario == 0 ) checked="checked"@endif>
                        <label for="suspender" class="font-weight-bolder text-uppercase text-danger">Suspender</label>
                        @error('nombre_usuario') <div class="validacion" >{{ $errors->first('estado_usuario')}}</div> @enderror
                    </div>
                </div>
                <div class="col-sm-6 ml-lg-4 ml-sm-0">
                    <div class="row">
                        <div class="form-group col-md-6">
                            <label for="txtNombre_usuario" class="font-weight-bolder text-uppercase">Nombre Usuario</label>
                            <input  id="txtNombre_usuario" class="form-control" type="text" name="nombre_usuario" value="{{ $usuario->nombre_usuario }}">
                            @error('nombre_usuario') <div class="validacion" >{{ $errors->first('nombre_usuario')}}</div> @enderror
                        </div>
                        <div class="form-group col-md-6">
                            <label for="txtApellido_correo" class="font-weight-bolder text-uppercase">Apellido Usuario</label>
                            <input  id="txtApellido_usuario" class="form-control" type="text" name="apellido_usuario" value="{{ $usuario->apellido_usuario }}">
                            @error('apellido_usuario') <div class="validacion" >{{ $errors->first('apellido_usuario')}}</div> @enderror
                        </div>
                        <div class="form-group col-md-6">
                            <label for="txtTelefono_Usuario" class="font-weight-bolder text-uppercase">Telefono Usuario</label>
                            <input  id="txtTelefono_Usuario" type="tel" class="form-control" name="telefono_usuario" placeholder="ejemplo +505812345678" value="{{ $usuario->telefono_usuario }}">
                            @error('telefono_usuario') <div class="validacion" >{{ $errors->first('telefono_usuario')}}</div> @enderror
                          </div>
                        <div class="form-group col-md-6">
                            <label for="txtemail" class="font-weight-bolder text-uppercase">Correo</label>
                            <input  id="txtemail" class="form-control" type="email"  name="correo_usuario" value="{{ $usuario->correo_usuario }}">
                            @error('correo_usuario') <div class="validacion" >{{ $errors->first('correo_usuario')}}</div> @enderror
                          </div>
                          <div class="form-group col-md-6">
                            <label for="sltTipo_Usuario" class="font-weight-bolder text-uppercase">Tipo de Usuario</label>
                            <select id="sltTipo_Usuario" class="form-control" name="tipo_usuario" >
                                @foreach ($tipos_usuarios as $tipo)
                                <option value="{{$tipo->id_tipo_usuario}}" @if ($tipo->id_tipo_usuario == $usuario->id_tipo_usuario) selected="selected" @endif>{{$tipo->nombre_tipo_usuario }}</option>    
                               @endforeach
                            </select>
                          </div>                         
                          <div class="form-group col-md-6">
                            <label for="sltCargo_Usuario" class="font-weight-bolder text-uppercase">Cargo de Usuario</label>
                            <select id="sltCargo_Usuario" class="form-control" name="cargo_usuario">
                                @foreach ($cargos_usuarios as $cargo)
                                <option value="{{$cargo->id_cargo_usuario}}"  @if ($cargo->id_cargo_usuario == $usuario->id_cargo_usuario) selected="selected" @endif>{{$cargo->nombre_cargo}}</option> 
                                @endforeach 
                            </select>
                          </div>
                          <div class="form-group col-md-6">
                            <label for="txtAlias_usuario" class="font-weight-bolder text-uppercase">Alias Usuario</label>
                            <input  id="txtAlias_usuario" class="form-control" type="text" name="alias_usuario" value="@if (old('alias_usuario') !== null ) {{old('alias_usuario')}}@else {{$usuario->alias}}@endif">
                            @error('alias_usuario') <div class="validacion" >{{ $errors->first('alias_usuario')}}</div> @enderror
                        </div>
                        <div class="form-group col-md-6">
                            <label for="txtcontraseña" class="font-weight-bolder text-uppercase">Contraseña Temporal</label>
                        <input  id="txtcontraseña" class="form-control" type="password" name="contraseña_usuario" value="{{ $usuario->contraseña}}">
                            @error('contraseña_usuario') <div class="validacion" >{{ $errors->first('contraseña_usuario')}}</div> @enderror
                            <div class="validacion" ></div>
                        </div>
                    </div>
                    <div class="text-left">
                        <button type="submit" class="btn btn-primary">Modificar Usuario</button>
                    </div>
                </div>  
            </div>

          </form>
    </div>
</div>
</x-master>

...

这是我得到的错误

SQLSTATE[42S22]:未找到列:1054 'where clause' 中的未知列 'alias_usuario'(SQL:select 计数(*)为从 usuarios 聚合,其中 alias_usuario = rytertertcc 和 id_usuario <> 4)

我查了官方laravel文档https://laravel.com/docs/8.x/validation#rule-unique 所以我开始实施这个 Rule::unique('usuarios')->ignore($usuario)] 所以如果我更新一个用户别名是唯一的数据但没有电子邮件或电话也是唯一的我应该没有这个问题的数据,

与此相关的另一个问题 Laravel: Validation unique on update 对此事没有用。

非常感谢您的帮助,非常感谢。

由于输入的名称与列名不匹配,您必须在创建规则时传递列名。根据 documentation,如果您的数据库使用的列与您传递的列不同,那么您还需要传递列名:

Rule::unique('usuarios', 'alias')->ignore($usuario)

你也可以这样做:

我不清楚你的数据库结构,但我可以给你举个例子:

users 是一个 table 名字。

名称 是您要验证的列。

'name' => 'unique:users,name,' . request('id')

在更新功能中你可以使用

'telefono_usuario' => 'unique:usuarios,telefono_usuario,' . $usuario->id_usuario,

telefono_usuario 作为您的字段名称

unique:usuarios 是你的模型

$usuario->id_usuario 是你要更新的id