format backend code

This commit is contained in:
Yisroel Baum 2026-05-25 20:24:59 +03:00
parent 9577367622
commit 67dd376a2f
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
40 changed files with 146 additions and 71 deletions

View file

@ -12,5 +12,6 @@ class CreateSessionDto
public User $user,
public DateTimeImmutable $createdAt,
public DateTimeImmutable $expiresAt,
) {}
) {
}
}

View file

@ -8,7 +8,9 @@ use DateTimeZone;
class EloquentSessionRepository implements SessionRepository
{
public function __construct(private UserRepository $userRepo) {}
public function __construct(private UserRepository $userRepo)
{
}
public function create(CreateSessionDto $dto): Session
{

View file

@ -12,7 +12,8 @@ class Session
private User $user,
private DateTimeImmutable $createdAt,
private DateTimeImmutable $expiresAt,
) {}
) {
}
public function getToken(): string
{

View file

@ -14,7 +14,8 @@ class AuthenticateUser
public function __construct(
private UserRepository $userRepo,
private PasswordHasher $hasher,
) {}
) {
}
/**
* @throws BadRequestException

View file

@ -7,5 +7,6 @@ class AuthenticateUserRequest
public function __construct(
public ?string $email,
public ?string $password,
) {}
) {
}
}

View file

@ -17,7 +17,8 @@ class CreateSession
private SessionRepository $sessionRepo,
private TokenGenerator $tokenGenerator,
private Clock $clock,
) {}
) {
}
public function execute(User $user): Session
{

View file

@ -8,7 +8,8 @@ class Logout
{
public function __construct(
private SessionRepository $sessionRepo,
) {}
) {
}
public function execute(string $token): void
{

View file

@ -20,7 +20,8 @@ class AuthController
private AuthenticateUser $authenticateUser,
private CreateSession $createSession,
private Logout $logout,
) {}
) {
}
public function login(Request $request): JsonResponse
{
@ -33,11 +34,13 @@ class AuthController
);
} catch (BadRequestException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 400
['error' => $exception->getMessage()],
400
);
} catch (UnauthorizedException $exception) {
return new JsonResponse(
['error' => $exception->getMessage()], 401
['error' => $exception->getMessage()],
401
);
}
@ -71,7 +74,7 @@ class AuthController
}
/**
* @return array{id: int, email: string, firstname: string, lastname: string}
* @return array{id: int, email: string}
*/
private function buildUserPayload(User $user): array
{

View file

@ -8,7 +8,9 @@ use Illuminate\Http\JsonResponse;
class SetController
{
public function __construct(private SetRepository $setRepository) {}
public function __construct(private SetRepository $setRepository)
{
}
public function index(): JsonResponse
{

View file

@ -10,5 +10,6 @@ class CreateElementDto
public Set $set,
public string $title,
public ?Element $parentElement,
) {}
) {
}
}

View file

@ -11,7 +11,8 @@ class Element
private string $title,
private Set $set,
private ?Element $parentElement,
) {}
) {
}
public function getId(): int
{

View file

@ -8,7 +8,9 @@ use DomainException;
class EloquentElementRepository implements ElementRepository
{
public function __construct(private SetRepository $setRepo) {}
public function __construct(private SetRepository $setRepo)
{
}
public function create(CreateElementDto $dto): Element
{

View file

@ -15,7 +15,8 @@ class CreateElement
public function __construct(
private ElementRepository $elementRepo,
private SetRepository $setRepo,
) {}
) {
}
/**
* @throws BadRequestException

View file

@ -8,5 +8,6 @@ class CreateElementRequest
public ?int $setId,
public ?string $title,
public ?int $parentElementId,
) {}
) {
}
}

View file

@ -4,4 +4,6 @@ namespace App\Exceptions;
use DomainException;
class BadRequestException extends DomainException {}
class BadRequestException extends DomainException
{
}

View file

@ -4,4 +4,6 @@ namespace App\Exceptions;
use DomainException;
class UnauthorizedException extends DomainException {}
class UnauthorizedException extends DomainException
{
}

View file

@ -16,7 +16,8 @@ class AuthMiddleware
public function __construct(
private SessionRepository $sessionRepo,
private Clock $clock,
) {}
) {
}
/**
* @param Closure(Request): Response $next

View file

@ -6,5 +6,6 @@ class CreateSetDto
{
public function __construct(
public string $name,
) {}
) {
}
}

View file

@ -7,7 +7,8 @@ class Set
public function __construct(
private int $id,
private string $name,
) {}
) {
}
public function getId(): int
{

View file

@ -18,15 +18,15 @@ final readonly class EmailAddress
$trimmed = trim($email);
if ($trimmed === '' || ! str_contains($trimmed, '@')) {
throw new InvalidArgumentException(self::ERROR_MESSAGE." $email");
throw new InvalidArgumentException(self::ERROR_MESSAGE . " $email");
}
[$local, $domain] = explode('@', $trimmed, 2);
$this->domain = mb_strtolower($domain);
$normalized = $local.'@'.$this->domain;
$normalized = $local . '@' . $this->domain;
if (filter_var($normalized, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException(self::ERROR_MESSAGE." $email");
throw new InvalidArgumentException(self::ERROR_MESSAGE . " $email");
}
$this->normalized = $normalized;

View file

@ -9,5 +9,6 @@ class CreateUserDto
public function __construct(
public EmailAddress $email,
public string $passwordHash,
) {}
) {
}
}

View file

@ -25,7 +25,7 @@ class EloquentUserRepository implements UserRepository
public function findByEmailDomain(string $domain): array
{
$models = UserModel::where('email', 'like', '%@'.$domain)->get();
$models = UserModel::where('email', 'like', '%@' . $domain)->get();
$users = [];
foreach ($models as $model) {
$users[] = $this->toDomain($model);

View file

@ -10,7 +10,8 @@ class User
private int $id,
private EmailAddress $email,
private string $passwordHash,
) {}
) {
}
public function getId(): int
{

View file

@ -9,12 +9,6 @@ use Illuminate\Database\Eloquent\Model;
* @property string $email
* @property string $password_hash
*
* @method static \Illuminate\Database\Eloquent\Builder<static>|UserModel newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|UserModel newQuery()
* @method static \Illuminate\Database\Eloquent\Builder<static>|UserModel query()
* @method static \Illuminate\Database\Eloquent\Builder<static>|UserModel whereEmail($value)
* @method static \Illuminate\Database\Eloquent\Builder<static>|UserModel whereId($value)
*
* @mixin \Eloquent
*/
class UserModel extends Model

View file

@ -95,7 +95,10 @@ return [
'passwords' => [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'table' => env(
'AUTH_PASSWORD_RESET_TOKEN_TABLE',
'password_reset_tokens'
),
'expire' => 60,
'throttle' => 60,
],

View file

@ -112,7 +112,10 @@ return [
|
*/
'prefix' => env('CACHE_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-cache-'),
'prefix' => env(
'CACHE_PREFIX',
Str::slug((string) env('APP_NAME', 'laravel')) . '-cache-'
),
/*
|--------------------------------------------------------------------------

View file

@ -111,7 +111,10 @@ return [
'prefix' => '',
'prefix_indexes' => true,
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
// 'trust_server_certificate' => env(
// 'DB_TRUST_SERVER_CERTIFICATE',
// 'false'
// ),
],
],
@ -149,7 +152,11 @@ return [
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-database-'),
'prefix' => env(
'REDIS_PREFIX',
Str::slug((string) env('APP_NAME', 'laravel'))
. '-database-'
),
'persistent' => env('REDIS_PERSISTENT', false),
],
@ -161,7 +168,10 @@ return [
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
'max_retries' => env('REDIS_MAX_RETRIES', 3),
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
'backoff_algorithm' => env(
'REDIS_BACKOFF_ALGORITHM',
'decorrelated_jitter'
),
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
],
@ -174,7 +184,10 @@ return [
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
'max_retries' => env('REDIS_MAX_RETRIES', 3),
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
'backoff_algorithm' => env(
'REDIS_BACKOFF_ALGORITHM',
'decorrelated_jitter'
),
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
],

View file

@ -41,7 +41,10 @@ return [
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => rtrim(env('APP_URL', 'http://localhost'), '/').'/storage',
'url' => rtrim(
env('APP_URL', 'http://localhost'),
'/'
) . '/storage',
'visibility' => 'public',
'throw' => false,
'report' => false,
@ -55,7 +58,10 @@ return [
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'use_path_style_endpoint' => env(
'AWS_USE_PATH_STYLE_ENDPOINT',
false
),
'throw' => false,
'report' => false,
],

View file

@ -89,7 +89,10 @@ return [
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'
. env('PAPERTRAIL_URL')
. ':'
. env('PAPERTRAIL_PORT'),
],
'processors' => [PsrLogMessageProcessor::class],
],

View file

@ -46,7 +46,13 @@ return [
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url((string) env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
'local_domain' => env(
'MAIL_EHLO_DOMAIN',
parse_url(
(string) env('APP_URL', 'http://localhost'),
PHP_URL_HOST
)
),
],
'ses' => [

View file

@ -57,7 +57,10 @@ return [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'prefix' => env(
'SQS_PREFIX',
'https://sqs.us-east-1.amazonaws.com/your-account-id'
),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),

View file

@ -129,7 +129,7 @@ return [
'cookie' => env(
'SESSION_COOKIE',
Str::slug((string) env('APP_NAME', 'laravel')).'-session'
Str::slug((string) env('APP_NAME', 'laravel')) . '-session'
),
/*
@ -193,7 +193,7 @@ return [
| take place, and can be used to mitigate CSRF attacks. By default, we
| will set this value to "lax" to permit secure cross-site requests.
|
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
| See MDN Set-Cookie SameSite documentation.
|
| Supported: "lax", "strict", "none", null
|

View file

@ -1,20 +1,23 @@
<?php
// phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
// Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
$maintenance = __DIR__ . '/../storage/framework/maintenance.php';
if (file_exists($maintenance)) {
require $maintenance;
}
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
require __DIR__ . '/../vendor/autoload.php';
// Bootstrap Laravel and handle the request...
/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';
$app = require_once __DIR__ . '/../bootstrap/app.php';
$app->handleRequest(Request::capture());

View file

@ -7,7 +7,9 @@ use DateTimeImmutable;
class FakeClock implements Clock
{
public function __construct(private DateTimeImmutable $currentTime) {}
public function __construct(private DateTimeImmutable $currentTime)
{
}
public function now(): DateTimeImmutable
{

View file

@ -12,7 +12,9 @@ class FakeTokenGenerator implements TokenGenerator
/**
* @param string[] $tokens
*/
public function __construct(private array $tokens) {}
public function __construct(private array $tokens)
{
}
public function generate(): string
{

View file

@ -31,7 +31,7 @@ class AuthMiddlewareTest extends TestCase
'2026-04-29T12:00:00',
new DateTimeZone('UTC')
);
$this->sessionRepo = new FakeSessionRepository;
$this->sessionRepo = new FakeSessionRepository();
$this->clock = new FakeClock($this->now);
$this->middleware = new AuthMiddleware(
$this->sessionRepo,
@ -58,7 +58,7 @@ class AuthMiddlewareTest extends TestCase
};
}
public function test_missing_cookie_returns_unauthorized_json(): void
public function testMissingCookieReturnsUnauthorizedJson(): void
{
$captured = null;
$response = $this->middleware->handle(
@ -74,7 +74,7 @@ class AuthMiddlewareTest extends TestCase
$this->assertNull($captured);
}
public function test_unknown_token_returns_unauthorized(): void
public function testUnknownTokenReturnsUnauthorized(): void
{
$captured = null;
$response = $this->middleware->handle(
@ -86,7 +86,7 @@ class AuthMiddlewareTest extends TestCase
$this->assertNull($captured);
}
public function test_expired_session_returns_unauthorized_and_is_deleted(): void
public function testExpiredSessionReturnsUnauthorizedAndIsDeleted(): void
{
$user = new User(
id: 7,
@ -113,7 +113,7 @@ class AuthMiddlewareTest extends TestCase
);
}
public function test_valid_session_attaches_user_and_calls_next(): void
public function testValidSessionAttachesUserAndCallsNext(): void
{
$user = new User(
id: 7,

View file

@ -25,7 +25,10 @@ class AuthenticateUserTest extends TestCase
$this->userRepo = new FakeUserRepository();
$this->hasher = new FakeHasher();
$this->authenticateUser = new AuthenticateUser($this->userRepo, $this->hasher);
$this->authenticateUser = new AuthenticateUser(
$this->userRepo,
$this->hasher
);
}
public function testAuthenticatesValidUser(): void

View file

@ -44,8 +44,14 @@ class CreateSessionTest extends TestCase
$this->assertSame('fake-token-123', $session->getToken());
$this->assertSame($user, $session->getUser());
$this->assertFalse($session->isExpired($this->clock->now()));
$this->assertSame('2026-05-18 12:00:00', $session->getCreatedAt()->format('Y-m-d H:i:s'));
$this->assertSame('2026-05-25 12:00:00', $session->getExpiresAt()->format('Y-m-d H:i:s'));
$this->assertSame(
'2026-05-18 12:00:00',
$session->getCreatedAt()->format('Y-m-d H:i:s')
);
$this->assertSame(
'2026-05-25 12:00:00',
$session->getExpiresAt()->format('Y-m-d H:i:s')
);
$stored = $this->sessionRepo->findByToken($session->getToken());
$this->assertNotNull($stored);

View file

@ -25,11 +25,11 @@ class LogoutTest extends TestCase
'2026-04-29T12:00:00',
new DateTimeZone('UTC')
);
$this->sessionRepo = new FakeSessionRepository;
$this->sessionRepo = new FakeSessionRepository();
$this->useCase = new Logout($this->sessionRepo);
}
public function test_existing_token_session_is_removed(): void
public function testExistingTokenSessionIsRemoved(): void
{
$this->sessionRepo->create(new CreateSessionDto(
token: 'token-abc',
@ -47,7 +47,7 @@ class LogoutTest extends TestCase
$this->assertNull($this->sessionRepo->findByToken('token-abc'));
}
public function test_unknown_token_does_not_throw(): void
public function testUnknownTokenDoesNotThrow(): void
{
$this->useCase->execute('unknown-token');

View file

@ -73,7 +73,7 @@ class AuthControllerTest extends TestCase
);
}
public function test_login_returns_200_and_sets_cookie_on_success(): void
public function testLoginReturns200AndSetsCookieOnSuccess(): void
{
$email = 'user@example.com';
$password = 'password';
@ -104,21 +104,21 @@ class AuthControllerTest extends TestCase
);
}
public function test_login_returns_400_when_email_missing(): void
public function testLoginReturns400WhenEmailMissing(): void
{
$request = new Request(['password' => 'correctpassword']);
$response = $this->controller->login($request);
$this->assertEquals(400, $response->getStatusCode());
}
public function test_login_returns_400_when_password_missing(): void
public function testLoginReturns400WhenPasswordMissing(): void
{
$request = new Request(['email' => 'user@example.com']);
$response = $this->controller->login($request);
$this->assertEquals(400, $response->getStatusCode());
}
public function test_login_returns_401_when_credentials_invalid(): void
public function testLoginReturns401WhenCredentialsInvalid(): void
{
$this->seedStartupUser('user@example.com', 'correctpassword');
@ -130,7 +130,7 @@ class AuthControllerTest extends TestCase
$this->assertEquals(401, $response->getStatusCode());
}
public function test_logout_returns_204_and_clears_cookie(): void
public function testLogoutReturns204AndClearsCookie(): void
{
$this->seedStartupUser('user@example.com', 'correctpassword');
$loginRequest = new Request([
@ -139,7 +139,7 @@ class AuthControllerTest extends TestCase
]);
$this->controller->login($loginRequest);
$logoutRequest = new Request;
$logoutRequest = new Request();
$logoutRequest->cookies->set(
AuthMiddleware::COOKIE_NAME,
'session-token-1'
@ -160,7 +160,7 @@ class AuthControllerTest extends TestCase
$this->assertSame('', $cookies[0]->getValue());
}
public function test_me_returns_200_with_user_when_authenticated(): void
public function testMeReturns200WithUserWhenAuthenticated(): void
{
$email = 'me@example.com';
$user = $this->userRepo->create(
@ -170,7 +170,7 @@ class AuthControllerTest extends TestCase
)
);
$request = new Request;
$request = new Request();
$request->attributes->set('user', $user);
$response = $this->controller->me($request);