chore: format and refactor the Connected Service component to use dto collection

This commit is contained in:
= 2026-05-11 07:42:09 +00:00
parent ca628fb009
commit 9443ac181c
35 changed files with 141 additions and 236 deletions

View File

@ -4,8 +4,7 @@
namespace App\Actions\Fortify; namespace App\Actions\Fortify;
use App\Concerns\PasswordValidationRules; use App\Concerns\{PasswordValidationRules, ProfileValidationRules};
use App\Concerns\ProfileValidationRules;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\CreatesNewUsers; use Laravel\Fortify\Contracts\CreatesNewUsers;

View File

@ -1,14 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Data\Ui\ConnectedServices;
use Illuminate\Support\Collection;
/**
* A collection of connected services.
*
* @extends Collection<int, ConnectedServiceData>
*/
final class ConnectedServiceCollectionData extends Collection {}

View File

@ -4,16 +4,11 @@
namespace App\Data\Ui\ConnectedServices; namespace App\Data\Ui\ConnectedServices;
use App\Enums\ConnectionStatus; use App\Enums\{ConnectionStatus, ConnectionTechTypes};
use App\Enums\ConnectionTechTypes;
use Livewire\Wireable;
use Spatie\LaravelData\Concerns\WireableData;
use Spatie\LaravelData\Data; use Spatie\LaravelData\Data;
final class ConnectedServiceData extends Data implements Wireable final class ConnectedServiceData extends Data
{ {
use WireableData;
public function __construct( public function __construct(
public string $name, public string $name,
public string $icon, public string $icon,

View File

@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Data\Ui\ConnectedServices;
use Livewire\Wireable;
use Spatie\LaravelData\Concerns\WireableData;
use Spatie\LaravelData\Data;
final class ConnectedServicesData extends Data implements Wireable
{
use WireableData;
public function __construct(
public ConnectedServiceCollectionData $services,
) {}
}

View File

@ -7,8 +7,7 @@
use App\Data\Users\UserData; use App\Data\Users\UserData;
use App\Enums\RolesStatus; use App\Enums\RolesStatus;
use Spatie\LaravelData\Attributes\DataCollectionOf; use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data; use Spatie\LaravelData\{Data, DataCollection};
use Spatie\LaravelData\DataCollection;
final class RoleData extends Data final class RoleData extends Data
{ {
@ -16,11 +15,11 @@ public function __construct(
public string $name, public string $name,
/** @var DataCollection<int, UserData> */ /** @var DataCollection<int, UserData> */
#[DataCollectionOf(class: UserData::class),] #[DataCollectionOf(class: UserData::class), ]
public DataCollection $users, public DataCollection $users,
/** @var DataCollection<int, ServiceData> */ /** @var DataCollection<int, ServiceData> */
#[DataCollectionOf(class: ServiceData::class),] #[DataCollectionOf(class: ServiceData::class), ]
public DataCollection $services, public DataCollection $services,
public RolesStatus $status, public RolesStatus $status,
) {} ) {}

View File

@ -4,8 +4,7 @@
namespace App\Livewire\Actions; namespace App\Livewire\Actions;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\{Auth, Session};
use Illuminate\Support\Facades\Session;
final class Logout final class Logout
{ {

View File

@ -8,8 +8,7 @@
use Flux\Flux; use Flux\Flux;
use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Computed; use Livewire\Attributes\{Computed, Title};
use Livewire\Attributes\Title;
use Livewire\Component; use Livewire\Component;
#[Title('Profile settings')] #[Title('Profile settings')]

View File

@ -9,15 +9,9 @@
use Flux\Flux; use Flux\Flux;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication; use Laravel\Fortify\Actions\{ConfirmTwoFactorAuthentication, DisableTwoFactorAuthentication, EnableTwoFactorAuthentication};
use Laravel\Fortify\Actions\DisableTwoFactorAuthentication; use Laravel\Fortify\{Features, Fortify};
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication; use Livewire\Attributes\{Computed, Locked, Title, Validate};
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Title;
use Livewire\Attributes\Validate;
use Livewire\Component; use Livewire\Component;
#[Title('Security settings')] #[Title('Security settings')]
@ -102,7 +96,7 @@ public function enable(EnableTwoFactorAuthentication $enableTwoFactorAuthenticat
{ {
$enableTwoFactorAuthentication(auth()->user()); $enableTwoFactorAuthentication(auth()->user());
if ( ! $this->requiresConfirmation) { if (! $this->requiresConfirmation) {
$this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication(); $this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication();
} }
@ -176,7 +170,7 @@ public function closeModal(): void
$this->resetErrorBag(); $this->resetErrorBag();
if ( ! $this->requiresConfirmation) { if (! $this->requiresConfirmation) {
$this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication(); $this->twoFactorEnabled = auth()->user()->hasEnabledTwoFactorAuthentication();
} }
} }

View File

@ -6,8 +6,7 @@
// use Illuminate\Contracts\Auth\MustVerifyEmail; // use Illuminate\Contracts\Auth\MustVerifyEmail;
use Database\Factories\UserFactory; use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Attributes\{Fillable, Hidden};
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
@ -20,6 +19,7 @@ final class User extends Authenticatable
{ {
/** @use HasFactory<UserFactory> */ /** @use HasFactory<UserFactory> */
use HasFactory; use HasFactory;
use Notifiable; use Notifiable;
use TwoFactorAuthenticatable; use TwoFactorAuthenticatable;
@ -31,7 +31,7 @@ public function initials(): string
return Str::of($this->name) return Str::of($this->name)
->explode(' ') ->explode(' ')
->take(2) ->take(2)
->map(fn($word) => Str::substr($word, 0, 1)) ->map(fn ($word) => Str::substr($word, 0, 1))
->implode(''); ->implode('');
} }

View File

@ -5,8 +5,7 @@
namespace App\Providers; namespace App\Providers;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Date; use Illuminate\Support\Facades\{DB, Date};
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rules\Password; use Illuminate\Validation\Rules\Password;
@ -37,7 +36,7 @@ protected function configureDefaults(): void
); );
Password::defaults( Password::defaults(
fn(): ?Password => app()->isProduction() fn (): ?Password => app()->isProduction()
? Password::min(12) ? Password::min(12)
->mixedCase() ->mixedCase()
->letters() ->letters()

View File

@ -4,13 +4,11 @@
namespace App\Providers; namespace App\Providers;
use App\Actions\Fortify\CreateNewUser; use App\Actions\Fortify\{CreateNewUser, ResetUserPassword};
use App\Actions\Fortify\ResetUserPassword;
use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\{ServiceProvider, Str};
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify; use Laravel\Fortify\Fortify;
final class FortifyServiceProvider extends ServiceProvider final class FortifyServiceProvider extends ServiceProvider
@ -44,13 +42,13 @@ private function configureActions(): void
*/ */
private function configureViews(): void private function configureViews(): void
{ {
Fortify::loginView(fn() => view('livewire.auth.login')); Fortify::loginView(fn () => view('livewire.auth.login'));
Fortify::verifyEmailView(fn() => view('livewire.auth.verify-email')); Fortify::verifyEmailView(fn () => view('livewire.auth.verify-email'));
Fortify::twoFactorChallengeView(fn() => view('livewire.auth.two-factor-challenge')); Fortify::twoFactorChallengeView(fn () => view('livewire.auth.two-factor-challenge'));
Fortify::confirmPasswordView(fn() => view('livewire.auth.confirm-password')); Fortify::confirmPasswordView(fn () => view('livewire.auth.confirm-password'));
Fortify::registerView(fn() => view('livewire.auth.register')); Fortify::registerView(fn () => view('livewire.auth.register'));
Fortify::resetPasswordView(fn() => view('livewire.auth.reset-password')); Fortify::resetPasswordView(fn () => view('livewire.auth.reset-password'));
Fortify::requestPasswordResetLinkView(fn() => view('livewire.auth.forgot-password')); Fortify::requestPasswordResetLinkView(fn () => view('livewire.auth.forgot-password'));
} }
/** /**
@ -58,10 +56,10 @@ private function configureViews(): void
*/ */
private function configureRateLimiting(): void private function configureRateLimiting(): void
{ {
RateLimiter::for('two-factor', fn(Request $request) => Limit::perMinute(5)->by($request->session()->get('login.id'))); RateLimiter::for('two-factor', fn (Request $request) => Limit::perMinute(5)->by($request->session()->get('login.id')));
RateLimiter::for('login', function (Request $request) { RateLimiter::for('login', function (Request $request) {
$throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())) . '|' . $request->ip()); $throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());
return Limit::perMinute(5)->by($throttleKey); return Limit::perMinute(5)->by($throttleKey);
}); });

View File

@ -4,9 +4,8 @@
namespace App\Providers; namespace App\Providers;
use Illuminate\Support\Arr; use Illuminate\Support\{Arr, ServiceProvider};
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
final class ScopeServiceProvider extends ServiceProvider final class ScopeServiceProvider extends ServiceProvider
{ {
@ -26,10 +25,10 @@ public function registerScopeDirective(): void
* *
* https://github.com/konradkalemba/blade-components-scoped-slots * https://github.com/konradkalemba/blade-components-scoped-slots
*/ */
Blade::directive("scope", function ($expression) { Blade::directive('scope', function ($expression) {
// Split the expression by `top-level` commas (not in parentheses) // Split the expression by `top-level` commas (not in parentheses)
$directiveArguments = preg_split("/,(?![^\(\(]*[\)\)])/", $expression); $directiveArguments = preg_split("/,(?![^\(\(]*[\)\)])/", $expression);
$directiveArguments = array_map("trim", $directiveArguments); $directiveArguments = array_map('trim', $directiveArguments);
// PHP 8.5 Safe Unpacking (Prevents "Undefined array key" crashes) // PHP 8.5 Safe Unpacking (Prevents "Undefined array key" crashes)
$name = $directiveArguments[0] ?? "''"; $name = $directiveArguments[0] ?? "''";
@ -40,7 +39,7 @@ public function registerScopeDirective(): void
$uses = array_flip($uses); $uses = array_flip($uses);
$uses[] = '$__env'; $uses[] = '$__env';
$uses[] = '$__bladeCompiler'; $uses[] = '$__bladeCompiler';
$uses = implode(",", $uses); $uses = implode(',', $uses);
/** /**
* Slot names can`t contains dot , eg: `user.city`. * Slot names can`t contains dot , eg: `user.city`.
@ -48,12 +47,12 @@ public function registerScopeDirective(): void
* *
* Later, on component it will be replaced back. * Later, on component it will be replaced back.
*/ */
$name = str_replace(".", "___", $name); $name = str_replace('.', '___', $name);
// PHP 8.5 Safe Loop Check // PHP 8.5 Safe Loop Check
return "<?php \$__bladeCompiler = \$__bladeCompiler ?? null; \$__env->slot({$name}, function({$functionArguments}) use ({$uses}) { \$loop = !empty(\$__env->getLoopStack()) ? (object) \$__env->getLoopStack()[0] : null; ?>"; return "<?php \$__bladeCompiler = \$__bladeCompiler ?? null; \$__env->slot({$name}, function({$functionArguments}) use ({$uses}) { \$loop = !empty(\$__env->getLoopStack()) ? (object) \$__env->getLoopStack()[0] : null; ?>";
}); });
Blade::directive("endscope", fn() => "<?php }); ?>"); Blade::directive('endscope', fn () => '<?php }); ?>');
} }
} }

View File

@ -6,9 +6,7 @@
use Closure; use Closure;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Illuminate\Support\Arr; use Illuminate\Support\{Arr, Carbon, Str};
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Illuminate\View\Component; use Illuminate\View\Component;
final class Table extends Component final class Table extends Component
@ -44,10 +42,8 @@ public function __construct(
// Remove closures from serialization // Remove closures from serialization
unset($this->rowDecoration, $this->cellDecoration, $this->headers); unset($this->rowDecoration, $this->cellDecoration, $this->headers);
// Serialize a unique ID for component tracking // Serialize a unique ID for component tracking
$this->uuid = "table-" . md5(serialize($this)) . $id; $this->uuid = 'table-'.md5(serialize($this)).$id;
// Restore closures // Restore closures
$this->rowDecoration = $rowDecoration; $this->rowDecoration = $rowDecoration;
@ -66,7 +62,7 @@ public function format(mixed $row, mixed $field, mixed $header): mixed
{ {
$format = $header['format'] ?? null; $format = $header['format'] ?? null;
if ( ! $format) { if (! $format) {
return $field; return $field;
} }
@ -75,7 +71,7 @@ public function format(mixed $row, mixed $field, mixed $header): mixed
} }
if ('currency' === $format[0]) { if ('currency' === $format[0]) {
return ($format[2] ?? '') . number_format((float) $field, ...mb_str_split($format[1])); return ($format[2] ?? '').number_format((float) $field, ...mb_str_split($format[1]));
} }
if ('date' === $format[0] && $field) { if ('date' === $format[0] && $field) {
@ -104,7 +100,7 @@ public function redirectLink(mixed $row): string
// Replace tokens with actual row values // Replace tokens with actual row values
$tokens->each(function (string $token) use ($row, &$link): void { $tokens->each(function (string $token) use ($row, &$link): void {
$link = Str::of($link)->replace("{" . $token . "}", data_get($row, $token))->toString(); $link = Str::of($link)->replace('{'.$token.'}', data_get($row, $token))->toString();
}); });
return $link; return $link;

View File

@ -3,13 +3,12 @@
declare(strict_types=1); declare(strict_types=1);
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\{Exceptions, Middleware};
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__)) return Application::configure(basePath: dirname(__DIR__))
->withRouting( ->withRouting(
web: __DIR__ . '/../routes/web.php', web: __DIR__.'/../routes/web.php',
commands: __DIR__ . '/../routes/console.php', commands: __DIR__.'/../routes/console.php',
health: '/up', health: '/up',
) )
->withMiddleware(function (Middleware $middleware): void {}) ->withMiddleware(function (Middleware $middleware): void {})

View File

@ -114,7 +114,7 @@
| |
*/ */
'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

@ -3,22 +3,11 @@
declare(strict_types=1); declare(strict_types=1);
use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Support\Arrayable;
use Spatie\LaravelData\Casts\DateTimeInterfaceCast; use Spatie\LaravelData\Casts\{DateTimeInterfaceCast, EnumCast};
use Spatie\LaravelData\Casts\EnumCast; use Spatie\LaravelData\Normalizers\{ArrayNormalizer, ArrayableNormalizer, JsonNormalizer, ModelNormalizer, ObjectNormalizer};
use Spatie\LaravelData\Normalizers\ArrayableNormalizer; use Spatie\LaravelData\RuleInferrers\{AttributesRuleInferrer, BuiltInTypesRuleInferrer, NullableRuleInferrer, RequiredRuleInferrer, SometimesRuleInferrer};
use Spatie\LaravelData\Normalizers\ArrayNormalizer;
use Spatie\LaravelData\Normalizers\JsonNormalizer;
use Spatie\LaravelData\Normalizers\ModelNormalizer;
use Spatie\LaravelData\Normalizers\ObjectNormalizer;
use Spatie\LaravelData\RuleInferrers\AttributesRuleInferrer;
use Spatie\LaravelData\RuleInferrers\BuiltInTypesRuleInferrer;
use Spatie\LaravelData\RuleInferrers\NullableRuleInferrer;
use Spatie\LaravelData\RuleInferrers\RequiredRuleInferrer;
use Spatie\LaravelData\RuleInferrers\SometimesRuleInferrer;
use Spatie\LaravelData\Support\Creation\ValidationStrategy; use Spatie\LaravelData\Support\Creation\ValidationStrategy;
use Spatie\LaravelData\Transformers\ArrayableTransformer; use Spatie\LaravelData\Transformers\{ArrayableTransformer, DateTimeInterfaceTransformer, EnumTransformer};
use Spatie\LaravelData\Transformers\DateTimeInterfaceTransformer;
use Spatie\LaravelData\Transformers\EnumTransformer;
return [ return [
/* /*
@ -26,36 +15,36 @@
* is an array, it will try to convert from the first format that works, * is an array, it will try to convert from the first format that works,
* and will serialize dates using the first format from the array. * and will serialize dates using the first format from the array.
*/ */
"date_format" => DATE_ATOM, 'date_format' => DATE_ATOM,
/* /*
* When transforming or casting dates, the following timezone will be used to * When transforming or casting dates, the following timezone will be used to
* convert the date to the correct timezone. If set to null no timezone will * convert the date to the correct timezone. If set to null no timezone will
* be passed. * be passed.
*/ */
"date_timezone" => null, 'date_timezone' => null,
/* /*
* It is possible to enable certain features of the package, these would otherwise * It is possible to enable certain features of the package, these would otherwise
* be breaking changes, and thus they are disabled by default. In the next major * be breaking changes, and thus they are disabled by default. In the next major
* version of the package, these features will be enabled by default. * version of the package, these features will be enabled by default.
*/ */
"features" => [ 'features' => [
"cast_and_transform_iterables" => false, 'cast_and_transform_iterables' => false,
/* /*
* When trying to set a computed property value, the package will throw an exception. * When trying to set a computed property value, the package will throw an exception.
* You can disable this behaviour by setting this option to true, which will then just * You can disable this behaviour by setting this option to true, which will then just
* ignore the value being passed into the computed property and recalculate it. * ignore the value being passed into the computed property and recalculate it.
*/ */
"ignore_exception_when_trying_to_set_computed_property_value" => false, 'ignore_exception_when_trying_to_set_computed_property_value' => false,
], ],
/* /*
* Global transformers will take complex types and transform them into simple * Global transformers will take complex types and transform them into simple
* types. * types.
*/ */
"transformers" => [ 'transformers' => [
DateTimeInterface::class => DateTimeInterfaceTransformer::class, DateTimeInterface::class => DateTimeInterfaceTransformer::class,
Arrayable::class => ArrayableTransformer::class, Arrayable::class => ArrayableTransformer::class,
BackedEnum::class => EnumTransformer::class, BackedEnum::class => EnumTransformer::class,
@ -65,7 +54,7 @@
* Global casts will cast values into complex types when creating a data * Global casts will cast values into complex types when creating a data
* object from simple types. * object from simple types.
*/ */
"casts" => [ 'casts' => [
DateTimeInterface::class => DateTimeInterfaceCast::class, DateTimeInterface::class => DateTimeInterfaceCast::class,
BackedEnum::class => EnumCast::class, BackedEnum::class => EnumCast::class,
// Enumerable::class => Spatie\LaravelData\Casts\EnumerableCast::class, // Enumerable::class => Spatie\LaravelData\Casts\EnumerableCast::class,
@ -76,7 +65,7 @@
* validation rules to properties of a data object based upon * validation rules to properties of a data object based upon
* the type of the property. * the type of the property.
*/ */
"rule_inferrers" => [ 'rule_inferrers' => [
SometimesRuleInferrer::class, SometimesRuleInferrer::class,
NullableRuleInferrer::class, NullableRuleInferrer::class,
RequiredRuleInferrer::class, RequiredRuleInferrer::class,
@ -89,7 +78,7 @@
* it cannot normalize the payload. The normalizers below are used for * it cannot normalize the payload. The normalizers below are used for
* every data object, unless overridden in a specific data object class. * every data object, unless overridden in a specific data object class.
*/ */
"normalizers" => [ 'normalizers' => [
ModelNormalizer::class, ModelNormalizer::class,
// Spatie\LaravelData\Normalizers\FormRequestNormalizer::class, // Spatie\LaravelData\Normalizers\FormRequestNormalizer::class,
ArrayableNormalizer::class, ArrayableNormalizer::class,
@ -103,7 +92,7 @@
* this key can be set globally here for all data objects. You can pass in * this key can be set globally here for all data objects. You can pass in
* `null` if you want to disable wrapping. * `null` if you want to disable wrapping.
*/ */
"wrap" => null, 'wrap' => null,
/* /*
* Adds a specific caster to the Symphony VarDumper component which hides * Adds a specific caster to the Symphony VarDumper component which hides
@ -111,7 +100,7 @@
* by `dump` or `dd`. Can be 'enabled', 'disabled' or 'development' * by `dump` or `dd`. Can be 'enabled', 'disabled' or 'development'
* which will only enable the caster locally. * which will only enable the caster locally.
*/ */
"var_dumper_caster_mode" => "development", 'var_dumper_caster_mode' => 'development',
/* /*
* It is possible to skip the PHP reflection analysis of data objects * It is possible to skip the PHP reflection analysis of data objects
@ -124,18 +113,18 @@
* in seconds if you want the cache to clear after a certain * in seconds if you want the cache to clear after a certain
* timeframe. * timeframe.
*/ */
"structure_caching" => [ 'structure_caching' => [
"enabled" => true, 'enabled' => true,
"directories" => [app_path("Data")], 'directories' => [app_path('Data')],
"cache" => [ 'cache' => [
"store" => env("CACHE_STORE", env("CACHE_DRIVER", "file")), 'store' => env('CACHE_STORE', env('CACHE_DRIVER', 'file')),
"prefix" => "laravel-data", 'prefix' => 'laravel-data',
"duration" => null, 'duration' => null,
], ],
"reflection_discovery" => [ 'reflection_discovery' => [
"enabled" => true, 'enabled' => true,
"base_path" => base_path(), 'base_path' => base_path(),
"root_namespace" => null, 'root_namespace' => null,
], ],
], ],
@ -144,23 +133,23 @@
* method. By default, only when a request is passed the data is being validated. This * method. By default, only when a request is passed the data is being validated. This
* behaviour can be changed to always validate or to completely disable validation. * behaviour can be changed to always validate or to completely disable validation.
*/ */
"validation_strategy" => ValidationStrategy::OnlyRequests->value, 'validation_strategy' => ValidationStrategy::OnlyRequests->value,
/* /*
* A data object can map the names of its properties when transforming (output) or when * A data object can map the names of its properties when transforming (output) or when
* creating (input). By default, the package will not map any names. You can set a * creating (input). By default, the package will not map any names. You can set a
* global strategy here, or override it on a specific data object. * global strategy here, or override it on a specific data object.
*/ */
"name_mapping_strategy" => [ 'name_mapping_strategy' => [
"input" => null, 'input' => null,
"output" => null, 'output' => null,
], ],
/* /*
* When using an invalid include, exclude, only or except partial, the package will * When using an invalid include, exclude, only or except partial, the package will
* throw an exception. You can disable this behaviour by setting this option to true. * throw an exception. You can disable this behaviour by setting this option to true.
*/ */
"ignore_invalid_partials" => false, 'ignore_invalid_partials' => false,
/* /*
* When transforming a nested chain of data objects, the package can end up in an infinite * When transforming a nested chain of data objects, the package can end up in an infinite
@ -168,39 +157,39 @@
* set as a safety measure to prevent this from happening. When set to null, the * set as a safety measure to prevent this from happening. When set to null, the
* package will not enforce a maximum depth. * package will not enforce a maximum depth.
*/ */
"max_transformation_depth" => null, 'max_transformation_depth' => null,
/* /*
* When the maximum transformation depth is reached, the package will throw an exception. * When the maximum transformation depth is reached, the package will throw an exception.
* You can disable this behaviour by setting this option to true which will return an * You can disable this behaviour by setting this option to true which will return an
* empty array. * empty array.
*/ */
"throw_when_max_transformation_depth_reached" => true, 'throw_when_max_transformation_depth_reached' => true,
/* /*
* When using the `make:data` command, the package will use these settings to generate * When using the `make:data` command, the package will use these settings to generate
* the data classes. You can override these settings by passing options to the command. * the data classes. You can override these settings by passing options to the command.
*/ */
"commands" => [ 'commands' => [
/* /*
* Provides default configuration for the `make:data` command. These settings can be overridden with options * Provides default configuration for the `make:data` command. These settings can be overridden with options
* passed directly to the `make:data` command for generating single Data classes, or if not set they will * passed directly to the `make:data` command for generating single Data classes, or if not set they will
* automatically fall back to these defaults. See `php artisan make:data --help` for more information * automatically fall back to these defaults. See `php artisan make:data --help` for more information
*/ */
"make" => [ 'make' => [
/* /*
* The default namespace for generated Data classes. This exists under the application's root namespace, * The default namespace for generated Data classes. This exists under the application's root namespace,
* so the default 'Data` will end up as '\App\Data', and generated Data classes will be placed in the * so the default 'Data` will end up as '\App\Data', and generated Data classes will be placed in the
* app/Data/ folder. Data classes can live anywhere, but this is where `make:data` will put them. * app/Data/ folder. Data classes can live anywhere, but this is where `make:data` will put them.
*/ */
"namespace" => "Data", 'namespace' => 'Data',
/* /*
* This suffix will be appended to all data classes generated by make:data, so that they are less likely * This suffix will be appended to all data classes generated by make:data, so that they are less likely
* to conflict with other related classes, controllers or models with a similar name without resorting * to conflict with other related classes, controllers or models with a similar name without resorting
* to adding an alias for the Data object. Set to a blank string (not null) to disable. * to adding an alias for the Data object. Set to a blank string (not null) to disable.
*/ */
"suffix" => "Data", 'suffix' => 'Data',
], ],
], ],
@ -209,7 +198,7 @@
* these synths will automatically handle the data objects and their * these synths will automatically handle the data objects and their
* properties when used in a Livewire component. * properties when used in a Livewire component.
*/ */
"livewire" => [ 'livewire' => [
"enable_synths" => true, 'enable_synths' => true,
], ],
]; ];

View File

@ -151,7 +151,7 @@
'options' => [ 'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'), '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), 'persistent' => env('REDIS_PERSISTENT', false),
], ],

View File

@ -43,7 +43,7 @@
'public' => [ 'public' => [
'driver' => 'local', 'driver' => 'local',
'root' => storage_path('app/public'), 'root' => storage_path('app/public'),
'url' => mb_rtrim(env('APP_URL', 'http://localhost'), '/') . '/storage', 'url' => mb_rtrim(env('APP_URL', 'http://localhost'), '/').'/storage',
'visibility' => 'public', 'visibility' => 'public',
'throw' => false, 'throw' => false,
'report' => false, 'report' => false,

View File

@ -2,9 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
use Monolog\Handler\NullHandler; use Monolog\Handler\{NullHandler, StreamHandler, SyslogUdpHandler};
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Processor\PsrLogMessageProcessor; use Monolog\Processor\PsrLogMessageProcessor;
return [ return [
@ -91,7 +89,7 @@
'handler_with' => [ 'handler_with' => [
'host' => env('PAPERTRAIL_URL'), 'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'), 'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://' . env('PAPERTRAIL_URL') . ':' . env('PAPERTRAIL_PORT'), 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
], ],
'processors' => [PsrLogMessageProcessor::class], 'processors' => [PsrLogMessageProcessor::class],
], ],

View File

@ -131,7 +131,7 @@
'cookie' => env( 'cookie' => env(
'SESSION_COOKIE', 'SESSION_COOKIE',
Str::slug((string) env('APP_NAME', 'laravel')) . '-session', Str::slug((string) env('APP_NAME', 'laravel')).'-session',
), ),
/* /*

View File

@ -30,7 +30,7 @@ public function definition(): array
'name' => fake()->name(), 'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(), 'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(), 'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'), 'password' => self::$password ??= Hash::make('password'),
'remember_token' => Str::random(10), 'remember_token' => Str::random(10),
'two_factor_secret' => null, 'two_factor_secret' => null,
'two_factor_recovery_codes' => null, 'two_factor_recovery_codes' => null,
@ -43,7 +43,7 @@ public function definition(): array
*/ */
public function unverified(): static public function unverified(): static
{ {
return $this->state(fn(array $attributes) => [ return $this->state(fn (array $attributes) => [
'email_verified_at' => null, 'email_verified_at' => null,
]); ]);
} }
@ -53,7 +53,7 @@ public function unverified(): static
*/ */
public function withTwoFactor(): static public function withTwoFactor(): static
{ {
return $this->state(fn(array $attributes) => [ return $this->state(fn (array $attributes) => [
'two_factor_secret' => encrypt('secret'), 'two_factor_secret' => encrypt('secret'),
'two_factor_recovery_codes' => encrypt(json_encode(['recovery-code-1'])), 'two_factor_recovery_codes' => encrypt(json_encode(['recovery-code-1'])),
'two_factor_confirmed_at' => now(), 'two_factor_confirmed_at' => now(),

View File

@ -6,7 +6,8 @@
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
return new class () extends Migration { return new class() extends Migration
{
/** /**
* Run the migrations. * Run the migrations.
*/ */

View File

@ -6,7 +6,8 @@
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
return new class () extends Migration { return new class() extends Migration
{
/** /**
* Run the migrations. * Run the migrations.
*/ */

View File

@ -6,7 +6,8 @@
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
return new class () extends Migration { return new class() extends Migration
{
/** /**
* Run the migrations. * Run the migrations.
*/ */

View File

@ -6,7 +6,8 @@
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
return new class () extends Migration { return new class() extends Migration
{
/** /**
* Run the migrations. * Run the migrations.
*/ */

View File

@ -1,21 +1,11 @@
{ {
"preset": "per", "preset": "laravel",
"rules": { "rules": {
"align_multiline_comment": true,
"array_indentation": true,
"array_syntax": true,
"blank_line_after_namespace": true,
"blank_line_after_opening_tag": true,
"combine_consecutive_issets": true,
"combine_consecutive_unsets": true,
"concat_space": {
"spacing": "one"
},
"declare_parentheses": true,
"declare_strict_types": true, "declare_strict_types": true,
"explicit_string_variable": true,
"final_class": true, "final_class": true,
"fully_qualified_strict_types": true, "fully_qualified_strict_types": true,
"group_import": true,
"single_import_per_statement": false,
"global_namespace_import": { "global_namespace_import": {
"import_classes": true, "import_classes": true,
"import_constants": true, "import_constants": true,
@ -23,14 +13,8 @@
}, },
"is_null": true, "is_null": true,
"lambda_not_used_import": true, "lambda_not_used_import": true,
"logical_operators": true,
"mb_str_functions": true,
"method_chaining_indentation": true,
"modernize_strpos": true,
"new_with_braces": true, "new_with_braces": true,
"no_empty_comment": true, "no_empty_comment": true,
"not_operator_with_space": true,
"ordered_traits": true,
"protected_to_private": true, "protected_to_private": true,
"simplified_if_return": true, "simplified_if_return": true,
"strict_comparison": true, "strict_comparison": true,
@ -38,7 +22,11 @@
"trim_array_spaces": true, "trim_array_spaces": true,
"use_arrow_functions": true, "use_arrow_functions": true,
"void_return": true, "void_return": true,
"yoda_style": true, "yoda_style": {
"equal": true,
"identical": true,
"less_and_greater": null
},
"array_push": true, "array_push": true,
"assign_null_coalescing_to_coalesce_equal": true, "assign_null_coalescing_to_coalesce_equal": true,
"explicit_indirect_variable": true, "explicit_indirect_variable": true,
@ -49,33 +37,21 @@
"no_superfluous_elseif": true, "no_superfluous_elseif": true,
"no_useless_else": true, "no_useless_else": true,
"nullable_type_declaration_for_default_null_value": true, "nullable_type_declaration_for_default_null_value": true,
"ordered_imports": {
"sort_algorithm": "alpha" "strict_param": true,
"date_time_immutable": true,
"mb_str_functions": true,
"logical_operators": true,
"ordered_interfaces": true,
"ordered_traits": true,
"php_unit_strict": true,
"phpdoc_align": {
"align": "vertical"
}, },
"ordered_class_elements": { "phpdoc_separation": true,
"order": [ "return_type_declaration": {
"use_trait", "space_before": "none"
"case", },
"constant", "single_line_throw": false
"constant_public",
"constant_protected",
"constant_private",
"property_public",
"property_protected",
"property_private",
"construct",
"destruct",
"magic",
"phpunit",
"method_abstract",
"method_public_static",
"method_public",
"method_protected_static",
"method_protected",
"method_private_static",
"method_private"
],
"sort_algorithm": "none"
}
} }
} }

View File

@ -8,15 +8,15 @@
define('LARAVEL_START', microtime(true)); define('LARAVEL_START', microtime(true));
// Determine if the application is in maintenance mode... // Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__ . '/../storage/framework/maintenance.php')) { if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance; require $maintenance;
} }
// Register the Composer autoloader... // Register the Composer autoloader...
require __DIR__ . '/../vendor/autoload.php'; require __DIR__.'/../vendor/autoload.php';
// Bootstrap Laravel and handle the request... // Bootstrap Laravel and handle the request...
/** @var Application $app */ /** @var Application $app */
$app = require_once __DIR__ . '/../bootstrap/app.php'; $app = require_once __DIR__.'/../bootstrap/app.php';
$app->handleRequest(Request::capture()); $app->handleRequest(Request::capture());

View File

@ -1,21 +1,20 @@
<?php <?php
use App\Data\Ui\ConnectedServices\ConnectedServiceCollectionData;
use App\Data\Ui\ConnectedServices\ConnectedServiceData; use App\Data\Ui\ConnectedServices\ConnectedServiceData;
use App\Data\Ui\ConnectedServices\ConnectedServicesData;
use App\Enums\ConnectionStatus; use App\Enums\ConnectionStatus;
use App\Enums\ConnectionTechTypes; use App\Enums\ConnectionTechTypes;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Livewire\Component; use Livewire\Component;
use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\DataCollection; use Spatie\LaravelData\DataCollection;
new class extends Component { new class extends Component {
public ConnectedServicesData $connectedServices; #[DataCollectionOf(ConnectedServiceData::class)]
public DataCollection $connectedServices;
public function mount(): void public function mount(): void
{ {
$this->connectedServices = new ConnectedServicesData( $this->connectedServices = ConnectedServiceData::collect([
services: new ConnectedServiceCollectionData([
new ConnectedServiceData( new ConnectedServiceData(
name: 'Microsoft Outlook', name: 'Microsoft Outlook',
icon: 'home', icon: 'home',
@ -44,14 +43,13 @@ public function mount(): void
connectionService: 'Redmine', connectionService: 'Redmine',
status: ConnectionStatus::Error status: ConnectionStatus::Error
), ),
]) ], DataCollection::class);
);
} }
}; };
?> ?>
<div class="flex overflow-x-auto gap-x-4"> <div class="flex overflow-x-auto gap-x-4">
@foreach ($connectedServices->services as $service) @foreach ($connectedServices as $service)
<x-shared.card class="min-w-60"> <x-shared.card class="min-w-60">
<div class="flex space-x-4"> <div class="flex space-x-4">
<div class="bg-blue-200 p-4 rounded-lg flex items-center justify-center max-h-10"> <div class="bg-blue-200 p-4 rounded-lg flex items-center justify-center max-h-10">

View File

@ -1,7 +1,6 @@
<?php <?php
use App\Data\Ui\ManageRoles\RoleData; use App\Data\Ui\ManageRoles\{RoleData,ServiceData};
use App\Data\Ui\ManageRoles\ServiceData;
use App\Data\Ui\TableHeader; use App\Data\Ui\TableHeader;
use App\Data\Users\UserData; use App\Data\Users\UserData;
use App\Enums\RolesStatus; use App\Enums\RolesStatus;

View File

@ -2,9 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
use App\Livewire\Settings\Appearance; use App\Livewire\Settings\{Appearance, Profile, Security};
use App\Livewire\Settings\Profile;
use App\Livewire\Settings\Security;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Features; use Laravel\Fortify\Features;

View File

@ -8,4 +8,4 @@
Route::livewire('dashboard', 'pages::dashboard')->name('dashboard'); Route::livewire('dashboard', 'pages::dashboard')->name('dashboard');
require __DIR__ . '/settings.php'; require __DIR__.'/settings.php';

View File

@ -4,8 +4,7 @@
use App\Models\User; use App\Models\User;
use Illuminate\Auth\Events\Verified; use Illuminate\Auth\Events\Verified;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\{Event, URL};
use Illuminate\Support\Facades\URL;
use Laravel\Fortify\Features; use Laravel\Fortify\Features;
beforeEach(function (): void { beforeEach(function (): void {
@ -36,7 +35,7 @@
Event::assertDispatched(Verified::class); Event::assertDispatched(Verified::class);
expect($user->fresh()->hasVerifiedEmail())->toBeTrue(); expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
$response->assertRedirect(route('dashboard', absolute: false) . '?verified=1'); $response->assertRedirect(route('dashboard', absolute: false).'?verified=1');
}); });
test('email is not verified with invalid hash', function (): void { test('email is not verified with invalid hash', function (): void {
@ -67,7 +66,7 @@
); );
$this->actingAs($user)->get($verificationUrl) $this->actingAs($user)->get($verificationUrl)
->assertRedirect(route('dashboard', absolute: false) . '?verified=1'); ->assertRedirect(route('dashboard', absolute: false).'?verified=1');
expect($user->fresh()->hasVerifiedEmail())->toBeTrue(); expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
Event::assertNotDispatched(Verified::class); Event::assertNotDispatched(Verified::class);

View File

@ -31,7 +31,7 @@
| |
*/ */
expect()->extend('toBeOne', fn() => $this->toBe(1)); expect()->extend('toBeOne', fn () => $this->toBe(1));
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -11,7 +11,7 @@ abstract class TestCase extends BaseTestCase
{ {
protected function skipUnlessFortifyHas(string $feature, ?string $message = null): void protected function skipUnlessFortifyHas(string $feature, ?string $message = null): void
{ {
if ( ! Features::enabled($feature)) { if (! Features::enabled($feature)) {
$this->markTestSkipped($message ?? "Fortify feature [{$feature}] is not enabled."); $this->markTestSkipped($message ?? "Fortify feature [{$feature}] is not enabled.");
} }
} }