feat: implement user registration functionality with validation and response handling

This commit is contained in:
ncoronel 2026-07-02 12:23:50 -03:00
parent 18eedd3209
commit a95cfc780b
16 changed files with 202 additions and 14 deletions

View File

@ -0,0 +1,27 @@
<?php
namespace App\Domains\Auth\Controllers;
use App\Domains\Auth\Requests\RegisterUserRequest;
use App\Domains\Auth\Resources\UserResource;
use App\Domains\Auth\Services\RegisterUserService;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
class RegisterController extends Controller
{
public function __construct(
protected RegisterUserService $registerUserService,
) {
}
public function __invoke(RegisterUserRequest $request): JsonResponse
{
$user = $this->registerUserService->register($request->validated());
return UserResource::make($user)
->additional(['message' => 'Usuario registrado correctamente.'])
->response()
->setStatusCode(201);
}
}

View File

@ -1,8 +1,7 @@
<?php
namespace App\Models;
namespace App\Domains\Auth\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
@ -10,16 +9,19 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
#[Fillable(['name', 'email', 'password'])]
#[Fillable(['nombre_apellido', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
/** @use HasFactory<UserFactory> */
use HasFactory, Notifiable;
protected static function newFactory(): UserFactory
{
return UserFactory::new();
}
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array

View File

@ -0,0 +1,26 @@
<?php
namespace App\Domains\Auth\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class RegisterUserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, mixed>
*/
public function rules(): array
{
return [
'nombre_apellido' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', Rule::unique('users', 'email')],
'password' => ['required', 'string', 'confirmed'],
];
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Domains\Auth\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* @mixin \App\Domains\Auth\Models\User
*/
class UserResource extends JsonResource
{
/**
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'nombre_apellido' => $this->nombre_apellido,
'email' => $this->email,
];
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Domains\Auth\Services;
use App\Domains\Auth\Models\User;
class RegisterUserService
{
/**
* @param array{nombre_apellido: string, email: string, password: string} $data
*/
public function register(array $data): User
{
return User::query()->create([
'nombre_apellido' => $data['nombre_apellido'],
'email' => $data['email'],
'password' => $data['password'],
]);
}
}

View File

@ -0,0 +1,6 @@
<?php
use App\Domains\Auth\Controllers\RegisterController;
use Illuminate\Support\Facades\Route;
Route::post('register', RegisterController::class);

View File

@ -2,9 +2,9 @@
namespace App\Domains\Cart\Models;
use App\Domains\Auth\Models\User;
use App\Domains\Catalog\Models\ProductVariant;
use App\Domains\Tenant\Models\Tenant;
use App\Models\User;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

View File

@ -3,8 +3,8 @@
namespace App\Domains\Cart\Services;
use App\Domains\Cart\Models\Cart;
use App\Domains\Auth\Models\User;
use App\Domains\Tenant\Models\Tenant;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Cookie;

View File

@ -2,8 +2,8 @@
namespace App\Domains\Purchase\Models;
use App\Domains\Auth\Models\User;
use App\Domains\Tenant\Models\Tenant;
use App\Models\User;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

View File

@ -1,6 +1,6 @@
<?php
use App\Models\User;
use App\Domains\Auth\Models\User;
return [

View File

@ -2,7 +2,7 @@
namespace Database\Factories;
use App\Models\User;
use App\Domains\Auth\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
@ -12,6 +12,8 @@ use Illuminate\Support\Str;
*/
class UserFactory extends Factory
{
protected $model = User::class;
/**
* The current password being used by the factory.
*/
@ -25,7 +27,7 @@ class UserFactory extends Factory
public function definition(): array
{
return [
'name' => fake()->name(),
'nombre_apellido' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),

View File

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table): void {
$table->renameColumn('name', 'nombre_apellido');
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table): void {
$table->renameColumn('nombre_apellido', 'name');
});
}
};

View File

@ -2,7 +2,7 @@
namespace Database\Seeders;
use App\Models\User;
use App\Domains\Auth\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
@ -18,7 +18,7 @@ class DatabaseSeeder extends Seeder
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'nombre_apellido' => 'Test User',
'email' => 'test@example.com',
]);

View File

@ -7,6 +7,7 @@ Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
require __DIR__.'/../app/Domains/Auth/routes/api.php';
require __DIR__.'/../app/Domains/Catalog/routes/api.php';
require __DIR__.'/../app/Domains/Cart/routes/api.php';
require __DIR__.'/../app/Domains/StorageTest/routes/api.php';

View File

@ -0,0 +1,58 @@
<?php
namespace Tests\Feature\Auth;
use App\Domains\Auth\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class RegisterControllerTest extends TestCase
{
use RefreshDatabase;
public function test_it_registers_a_user(): void
{
$response = $this->postJson('/api/register', [
'nombre_apellido' => 'Ada Lovelace',
'email' => 'ada@example.com',
'password' => 'secret123',
'password_confirmation' => 'secret123',
]);
$response
->assertCreated()
->assertJsonPath('message', 'Usuario registrado correctamente.')
->assertJsonPath('data.nombre_apellido', 'Ada Lovelace')
->assertJsonPath('data.email', 'ada@example.com');
$this->assertDatabaseHas('users', [
'nombre_apellido' => 'Ada Lovelace',
'email' => 'ada@example.com',
]);
$user = User::query()->where('email', 'ada@example.com')->firstOrFail();
$this->assertNotSame('secret123', $user->password);
}
public function test_it_validates_required_fields_and_unique_email(): void
{
User::factory()->create([
'nombre_apellido' => 'Existing User',
'email' => 'existing@example.com',
]);
$response = $this->postJson('/api/register', [
'nombre_apellido' => '',
'email' => 'existing@example.com',
'password' => 'secret123',
'password_confirmation' => 'different-secret',
]);
$response->assertUnprocessable()->assertJsonValidationErrors([
'nombre_apellido',
'email',
'password',
]);
}
}

View File

@ -2,13 +2,13 @@
namespace Tests\Feature\Cart;
use App\Domains\Auth\Models\User;
use App\Domains\Catalog\Models\Product;
use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\ProductVariant;
use App\Domains\Catalog\Models\ProductAttribute;
use App\Domains\Catalog\Models\ProductVariantDefinition;
use App\Domains\Tenant\Models\Tenant;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;