Version 0.7.0 #1
94
app/Console/Commands/CreateUserAdmin.php
Normal file
94
app/Console/Commands/CreateUserAdmin.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Dto\User\ManyRoleDto;
|
||||
use App\Enums\SystemRole;
|
||||
use App\Repositories\RoleRepository;
|
||||
use App\Services\User\UserCommandHandler;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator as ValidatorFacade;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
final class CreateUserAdmin extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:create-user-admin {email} {password}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Create admin user.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(UserCommandHandler $userCommandHandler, RoleRepository $roleRepository): void
|
||||
{
|
||||
$validator = $this->getData();
|
||||
|
||||
if ($validator->fails()) {
|
||||
$this->errorMessageAndStop($validator->errors()->all());
|
||||
}
|
||||
$data = $validator->valid();
|
||||
|
||||
try {
|
||||
$role = $roleRepository->getRoleBySlug(SystemRole::Admin->value);
|
||||
if (is_null($role)) {
|
||||
$this->errorMessageAndStop('Administrator role not found.');
|
||||
}
|
||||
$user = DB::transaction(function () use($data, $userCommandHandler, $role) {
|
||||
$data['name'] = 'Administrator';
|
||||
$user = $userCommandHandler->handleStore($data, $data['password']);
|
||||
$userCommandHandler->handleConfirmationByEmail($user);
|
||||
$roles = new ManyRoleDto([$role->id]);
|
||||
$userCommandHandler->handleSyncRoles($user, $roles);
|
||||
|
||||
return $user;
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
$this->errorMessageAndStop($e->getMessage());
|
||||
}
|
||||
|
||||
$this->info('The command was successful!');
|
||||
}
|
||||
|
||||
private function getData(): Validator
|
||||
{
|
||||
return ValidatorFacade::make([
|
||||
'email' => $this->argument('email'),
|
||||
'password' => $this->argument('password'),
|
||||
], [
|
||||
'email' => ['required', 'email', 'unique:users,email'],
|
||||
'password' => ['required', Password::default()],
|
||||
]);
|
||||
}
|
||||
|
||||
private function stop(): never
|
||||
{
|
||||
exit;
|
||||
}
|
||||
|
||||
private function errorMessageAndStop(string | array $error): never
|
||||
{
|
||||
$this->info('User not created. See error messages below:');
|
||||
|
||||
if (is_array($error)) {
|
||||
foreach ($error as $err) {
|
||||
$this->error($err);
|
||||
}
|
||||
} else {
|
||||
$this->error($error);
|
||||
}
|
||||
|
||||
$this->stop();
|
||||
}
|
||||
}
|
32
app/Dto/User/ManyRoleDto.php
Normal file
32
app/Dto/User/ManyRoleDto.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\User;
|
||||
|
||||
use App\Exceptions\Dto\User\ManyRoleDtoException;
|
||||
|
||||
final class ManyRoleDto
|
||||
{
|
||||
private array $roles = [];
|
||||
|
||||
public function __construct(array $roles = []) {
|
||||
foreach ($roles as $role) {
|
||||
if (!is_numeric($role) || is_float($role)) {
|
||||
throw new ManyRoleDtoException('Not an integer: ' . $role . '.');
|
||||
}
|
||||
$this->add((int) $role);
|
||||
}
|
||||
}
|
||||
|
||||
public function add(int $id): void
|
||||
{
|
||||
if ($id < 1) {
|
||||
throw new ManyRoleDtoException('Only Integer > 0.');
|
||||
}
|
||||
$this->roles[] = $id;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->roles;
|
||||
}
|
||||
}
|
8
app/Exceptions/Dto/User/ManyRoleDtoException.php
Normal file
8
app/Exceptions/Dto/User/ManyRoleDtoException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Exceptions\Dto\User;
|
||||
|
||||
final class ManyRoleDtoException extends \Exception
|
||||
{
|
||||
|
||||
}
|
59
app/Models/Role.php
Normal file
59
app/Models/Role.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Enums\SystemRoleEnum;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\hasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
final class Role extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'slug'
|
||||
];
|
||||
|
||||
public function scopeLatest(Builder $query): Builder
|
||||
{
|
||||
return $query->orderBy('id', 'desc');
|
||||
}
|
||||
|
||||
public function scopeAlphavit(Builder $query): Builder
|
||||
{
|
||||
return $query->orderBy('name', 'asc');
|
||||
}
|
||||
|
||||
public function permissions(): hasMany
|
||||
{
|
||||
return $this->hasMany(RolePermission::class, 'role_id', 'id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Проверяем можем мы удалять эту группу или нет.
|
||||
* Есть системные группы, которые нельзя удалять.
|
||||
*/
|
||||
public function isRemove(): bool
|
||||
{
|
||||
$dontRemove = SystemRoleEnum::toArray();
|
||||
return (array_search($this->slug, $dontRemove) === false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка эта группа самая главная или нет.
|
||||
*/
|
||||
public function isAdmin(): bool
|
||||
{
|
||||
return ($this->slug === SystemRoleEnum::Admin->value);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
@ -13,6 +14,15 @@ final class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, HasFactory, Notifiable, SoftDeletes;
|
||||
|
||||
/**
|
||||
* The model's default values for attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'is_active' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
@ -46,4 +56,12 @@ final class User extends Authenticatable
|
||||
'email_verified_at' => 'datetime',
|
||||
'is_active' => 'boolean'
|
||||
];
|
||||
|
||||
/**
|
||||
* Return the user's roles
|
||||
*/
|
||||
public function roles(): belongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Role::class);
|
||||
}
|
||||
}
|
||||
|
13
app/Repositories/RoleRepository.php
Normal file
13
app/Repositories/RoleRepository.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\Role;
|
||||
|
||||
final readonly class RoleRepository
|
||||
{
|
||||
public function getRoleBySlug(string $slug): ?Role
|
||||
{
|
||||
return Role::query()->where('slug', $slug)->first();
|
||||
}
|
||||
}
|
57
app/Services/User/UserCommandHandler.php
Normal file
57
app/Services/User/UserCommandHandler.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Services\User;
|
||||
|
||||
use App\Dto\User\ManyRoleDto;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final readonly class UserCommandHandler
|
||||
{
|
||||
public function handleStore(array $data, int|string $password): User
|
||||
{
|
||||
$data['email'] = Str::lower($data['email']);
|
||||
$data['password'] = $this->hashPassword($password);
|
||||
$user = User::create($data);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function handleUpdate(User $user, array $data): User
|
||||
{
|
||||
if (isset($data['email'])) {
|
||||
$data['email'] = Str::lower($data['email']);
|
||||
}
|
||||
|
||||
if (isset($data['password'])) {
|
||||
unset($data['password']);
|
||||
}
|
||||
|
||||
$user->update($data);
|
||||
$user->touch();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function handleConfirmationByEmail(User $user): void
|
||||
{
|
||||
$user->update(['email_verified_at' => new Carbon('NOW')]);
|
||||
}
|
||||
|
||||
public function handleUpdatePassword(User $user, int|string $password): void
|
||||
{
|
||||
$user->update(['password' => $this->hashPassword($password)]);
|
||||
}
|
||||
|
||||
public function handleSyncRoles(User $user, ManyRoleDto $roles): void
|
||||
{
|
||||
$user->roles()->sync($roles->toArray());
|
||||
}
|
||||
|
||||
private function hashPassword(int|string $password): string
|
||||
{
|
||||
return Hash::make($password);
|
||||
}
|
||||
}
|
60
database/migrations/2023_06_28_155124_create_roles.php
Normal file
60
database/migrations/2023_06_28_155124_create_roles.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('roles', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('slug')->unique();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
|
||||
DB::table('roles')->insert([
|
||||
'name' => 'Administrator',
|
||||
'slug' => 'admin',
|
||||
'created_at' => Carbon::now(),
|
||||
'updated_at' => Carbon::now()
|
||||
]);
|
||||
|
||||
Schema::create('role_user', function (Blueprint $table) {
|
||||
$table->unsignedBigInteger('user_id')->index();
|
||||
$table->unsignedBigInteger('role_id');
|
||||
$table->foreign('user_id')->references('id')->on('users');
|
||||
$table->foreign('role_id')->references('id')->on('roles');
|
||||
$table->primary(['user_id', 'role_id']);
|
||||
});
|
||||
|
||||
Schema::create('role_permission', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('role_id')->index();
|
||||
$table->string('permission');
|
||||
$table->foreign('role_id')->references('id')->on('roles');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('role_permission');
|
||||
Schema::dropIfExists('role_user');
|
||||
Schema::dropIfExists('roles');
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user