diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000..5aea046 --- /dev/null +++ b/.env.testing @@ -0,0 +1,25 @@ +APP_NAME=DishPlanner +APP_ENV=testing +APP_KEY=base64:2ADW3imsmRMo+UDw3GR6852wQu37/aNK1ooxEdaJIC0= +APP_DEBUG=true +APP_URL=http://localhost + +APP_MAINTENANCE_DRIVER=file + +BCRYPT_ROUNDS=4 + +LOG_CHANNEL=stack +LOG_STACK=single + +DB_CONNECTION=sqlite +DB_DATABASE=:memory: + +SESSION_DRIVER=array + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=sync + +CACHE_STORE=array + +MAIL_MAILER=array diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..b51e604 --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: ['release/*'] + pull_request: + branches: [main, 'release/*'] + +jobs: + ci: + runs-on: docker + container: + image: forge.lvl0.xyz/lvl0/dishplanner-ci:php8.3-1 + steps: + - uses: https://data.forgejo.org/actions/checkout@v4 + + - name: Cache Composer dependencies + uses: https://data.forgejo.org/actions/cache@v4 + with: + path: ~/.cache/composer + key: composer-${{ hashFiles('composer.lock') }} + restore-keys: composer- + + - name: Install dependencies + run: composer install --no-interaction --prefer-dist + + - name: Prepare environment + run: cp .env.testing .env + + - name: Lint + run: vendor/bin/pint --test + + - name: Static analysis + run: vendor/bin/phpstan analyse --memory-limit=1G + + - name: Tests + run: php -d memory_limit=512M vendor/bin/phpunit diff --git a/app/Actions/User/CreateUserAction.php b/app/Actions/User/CreateUserAction.php index 07e91a9..f3c8952 100644 --- a/app/Actions/User/CreateUserAction.php +++ b/app/Actions/User/CreateUserAction.php @@ -17,11 +17,11 @@ public function execute(array $data): User { try { // Validate required fields first - if (!isset($data['name']) || empty($data['name'])) { + if (! isset($data['name']) || empty($data['name'])) { throw new InvalidArgumentException('Name is required'); } - if (!isset($data['planner_id']) || empty($data['planner_id'])) { + if (! isset($data['planner_id']) || empty($data['planner_id'])) { throw new InvalidArgumentException('Planner ID is required'); } @@ -38,7 +38,7 @@ public function execute(array $data): User 'planner_id' => $data['planner_id'], ]); - if (!$user) { + if (! $user) { throw new Exception('User creation returned null'); } @@ -50,7 +50,7 @@ public function execute(array $data): User // Verify the user was actually created $createdUser = User::find($user->id); - if (!$createdUser) { + if (! $createdUser) { throw new Exception('User creation did not persist to database'); } diff --git a/app/Actions/User/EditUserAction.php b/app/Actions/User/EditUserAction.php index ccb931a..e5b31e3 100644 --- a/app/Actions/User/EditUserAction.php +++ b/app/Actions/User/EditUserAction.php @@ -12,52 +12,52 @@ public function execute(User $user, array $data): bool { try { DB::beginTransaction(); - + Log::info('EditUserAction: Starting user update', [ 'user_id' => $user->id, 'old_name' => $user->name, 'new_name' => $data['name'], 'planner_id' => $user->planner_id, ]); - + $result = $user->update([ 'name' => $data['name'], ]); - + Log::info('EditUserAction: Update result', [ 'result' => $result, 'user_id' => $user->id, ]); - - if (!$result) { + + if (! $result) { throw new \Exception('User update returned false'); } - + // Verify the update actually happened $user->refresh(); if ($user->name !== $data['name']) { throw new \Exception('User update did not persist to database'); } - + DB::commit(); - + Log::info('EditUserAction: User successfully updated', [ 'user_id' => $user->id, 'updated_name' => $user->name, ]); - + return true; - + } catch (\Exception $e) { DB::rollBack(); - + Log::error('EditUserAction: User update failed', [ 'user_id' => $user->id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); - + throw $e; } } -} \ No newline at end of file +} diff --git a/app/Console/Commands/GenerateSchedulesCommand.php b/app/Console/Commands/GenerateSchedulesCommand.php index 98271bd..b62ae0e 100644 --- a/app/Console/Commands/GenerateSchedulesCommand.php +++ b/app/Console/Commands/GenerateSchedulesCommand.php @@ -24,6 +24,7 @@ public function handle(): int if ($planners->isEmpty()) { $this->warn('No planners found. Aborting schedule generation.'); + return self::FAILURE; } diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php index a87c877..fa4df3f 100755 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@ -13,8 +13,7 @@ public function response( ?array $payload = null, array|string|null $errors = null, int $statusCode = 200, - ): JsonResponse - { + ): JsonResponse { return response()->json(resolve(OutputService::class)->response($success, $payload, $errors), $statusCode); } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 80375a9..ded9ff5 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -41,4 +41,4 @@ public function logout(Request $request) return redirect('/'); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index 8a4c546..4a08f82 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -34,4 +34,4 @@ public function register(Request $request) return redirect(route('dashboard')); } -} \ No newline at end of file +} diff --git a/app/Http/Resources/UserDishResource.php b/app/Http/Resources/UserDishResource.php index 2f7acb6..6aefd46 100644 --- a/app/Http/Resources/UserDishResource.php +++ b/app/Http/Resources/UserDishResource.php @@ -17,7 +17,7 @@ public function toArray(Request $request): array 'recurrences' => $this->recurrences->map(fn ($recurrence) => [ 'id' => $recurrence->id, 'type' => $recurrence->recurrence_type, - 'value' => $recurrence->getValue() + 'value' => $recurrence->getValue(), ]), ]; } diff --git a/app/Livewire/Dishes/DishesList.php b/app/Livewire/Dishes/DishesList.php index ffe8049..f7809c9 100644 --- a/app/Livewire/Dishes/DishesList.php +++ b/app/Livewire/Dishes/DishesList.php @@ -12,16 +12,20 @@ class DishesList extends Component use WithPagination; public $showCreateModal = false; + public $showEditModal = false; + public $showDeleteModal = false; - + public $editingDish = null; + public $deletingDish = null; - + // Form fields public $name = ''; + public $selectedUsers = []; - + protected $rules = [ 'name' => 'required|string|max:255', 'selectedUsers' => 'array', @@ -32,14 +36,14 @@ public function render() $dishes = Dish::with('users') ->orderBy('name') ->paginate(10); - + $users = User::where('planner_id', auth()->id()) ->orderBy('name') ->get(); - + return view('livewire.dishes.dishes-list', [ 'dishes' => $dishes, - 'users' => $users + 'users' => $users, ]); } @@ -60,13 +64,13 @@ public function store() ]); // Attach selected users - if (!empty($this->selectedUsers)) { + if (! empty($this->selectedUsers)) { $dish->users()->attach($this->selectedUsers); } $this->showCreateModal = false; $this->reset(['name', 'selectedUsers']); - + session()->flash('success', 'Dish created successfully.'); } @@ -86,13 +90,13 @@ public function update() $this->editingDish->update([ 'name' => $this->name, ]); - + // Sync users $this->editingDish->users()->sync($this->selectedUsers); $this->showEditModal = false; $this->reset(['name', 'selectedUsers', 'editingDish']); - + session()->flash('success', 'Dish updated successfully.'); } @@ -108,7 +112,7 @@ public function delete() $this->deletingDish->delete(); $this->showDeleteModal = false; $this->deletingDish = null; - + session()->flash('success', 'Dish deleted successfully.'); } @@ -126,7 +130,7 @@ public function toggleAllUsers(): void if (count($this->selectedUsers) === $users->count()) { $this->selectedUsers = []; } else { - $this->selectedUsers = $users->pluck('id')->map(fn($id) => (string) $id)->toArray(); + $this->selectedUsers = $users->pluck('id')->map(fn ($id) => (string) $id)->toArray(); } } -} \ No newline at end of file +} diff --git a/app/Livewire/Schedule/ScheduleCalendar.php b/app/Livewire/Schedule/ScheduleCalendar.php index 9d2a911..19e100f 100644 --- a/app/Livewire/Schedule/ScheduleCalendar.php +++ b/app/Livewire/Schedule/ScheduleCalendar.php @@ -19,25 +19,39 @@ class ScheduleCalendar extends Component { public $currentMonth; + public $currentYear; + public $calendarDays = []; + public $showRegenerateModal = false; + public $regenerateDate = null; + public $regenerateUserId = null; // Edit dish modal public $showEditDishModal = false; + public $editDate = null; + public $editUserId = null; + public $selectedDishId = null; + public $availableDishes = []; // Add dish modal public $showAddDishModal = false; + public $addDate = null; + public $addUserIds = []; + public $addSelectedDishId = null; + public $addAvailableUsers = []; + public $addAvailableDishes = []; public function mount(): void @@ -61,7 +75,7 @@ public function refreshCalendar(): void public function loadCalendar(): void { - $service = new ScheduleCalendarService(); + $service = new ScheduleCalendarService; $this->calendarDays = $service->getCalendarDays( auth()->user(), $this->currentMonth, @@ -93,8 +107,9 @@ public function nextMonth(): void public function regenerateForUserDate($date, $userId): void { - if (!$this->authorizeUser($userId)) { + if (! $this->authorizeUser($userId)) { session()->flash('error', 'Unauthorized action.'); + return; } @@ -106,12 +121,13 @@ public function regenerateForUserDate($date, $userId): void public function confirmRegenerate(): void { try { - if (!$this->authorizeUser($this->regenerateUserId)) { + if (! $this->authorizeUser($this->regenerateUserId)) { session()->flash('error', 'Unauthorized action.'); + return; } - $action = new DeleteScheduledUserDishForDateAction(); + $action = new DeleteScheduledUserDishForDateAction; $action->execute( auth()->user(), Carbon::parse($this->regenerateDate), @@ -131,12 +147,13 @@ public function confirmRegenerate(): void public function skipDay($date, $userId): void { try { - if (!$this->authorizeUser($userId)) { + if (! $this->authorizeUser($userId)) { session()->flash('error', 'Unauthorized action.'); + return; } - $action = new SkipScheduledUserDishForDateAction(); + $action = new SkipScheduledUserDishForDateAction; $action->execute( auth()->user(), Carbon::parse($date), @@ -155,6 +172,7 @@ public function skipDay($date, $userId): void private function authorizeUser(int $userId): bool { $user = User::find($userId); + return $user && $user->planner_id === auth()->id(); } @@ -179,8 +197,9 @@ public function cancel(): void public function removeDish($date, $userId): void { try { - if (!$this->authorizeUser($userId)) { + if (! $this->authorizeUser($userId)) { session()->flash('error', 'Unauthorized action.'); + return; } @@ -223,7 +242,7 @@ public function toggleAllUsers(): void if (count($this->addUserIds) === count($this->addAvailableUsers)) { $this->addUserIds = []; } else { - $this->addUserIds = $this->addAvailableUsers->pluck('id')->map(fn($id) => (string) $id)->toArray(); + $this->addUserIds = $this->addAvailableUsers->pluck('id')->map(fn ($id) => (string) $id)->toArray(); } $this->updateAvailableDishes(); } @@ -252,11 +271,13 @@ public function saveAddDish(): void try { if (empty($this->addUserIds)) { session()->flash('error', 'Please select at least one user.'); + return; } - if (!$this->addSelectedDishId) { + if (! $this->addSelectedDishId) { session()->flash('error', 'Please select a dish.'); + return; } @@ -273,8 +294,9 @@ public function saveAddDish(): void $skippedCount = 0; foreach ($this->addUserIds as $userId) { - if (!$this->authorizeUser((int) $userId)) { + if (! $this->authorizeUser((int) $userId)) { $skippedCount++; + continue; } @@ -285,6 +307,7 @@ public function saveAddDish(): void if ($existing) { $skippedCount++; + continue; } @@ -293,8 +316,9 @@ public function saveAddDish(): void ->where('dish_id', $this->addSelectedDishId) ->first(); - if (!$userDish) { + if (! $userDish) { $skippedCount++; + continue; } @@ -336,8 +360,9 @@ private function closeAddDishModal(): void public function editDish($date, $userId): void { - if (!$this->authorizeUser($userId)) { + if (! $this->authorizeUser($userId)) { session()->flash('error', 'Unauthorized action.'); + return; } @@ -370,13 +395,15 @@ public function editDish($date, $userId): void public function saveDish(): void { try { - if (!$this->authorizeUser($this->editUserId)) { + if (! $this->authorizeUser($this->editUserId)) { session()->flash('error', 'Unauthorized action.'); + return; } - if (!$this->selectedDishId) { + if (! $this->selectedDishId) { session()->flash('error', 'Please select a dish.'); + return; } @@ -394,8 +421,9 @@ public function saveDish(): void ->where('dish_id', $this->selectedDishId) ->first(); - if (!$userDish) { + if (! $userDish) { session()->flash('error', 'This dish is not assigned to this user.'); + return; } @@ -427,7 +455,8 @@ public function saveDish(): void public function getMonthNameProperty(): string { - $service = new ScheduleCalendarService(); + $service = new ScheduleCalendarService; + return $service->getMonthName($this->currentMonth, $this->currentYear); } } diff --git a/app/Livewire/Schedule/ScheduleGenerator.php b/app/Livewire/Schedule/ScheduleGenerator.php index a2f3b71..fc2f361 100644 --- a/app/Livewire/Schedule/ScheduleGenerator.php +++ b/app/Livewire/Schedule/ScheduleGenerator.php @@ -7,19 +7,27 @@ use DishPlanner\Schedule\Actions\ClearScheduleForMonthAction; use DishPlanner\Schedule\Actions\GenerateScheduleForMonthAction; use DishPlanner\Schedule\Actions\RegenerateScheduleForDateForUsersAction; +use Illuminate\Contracts\View\Factory; +use Illuminate\Contracts\View\View; use Illuminate\Support\Facades\Log; use Livewire\Component; class ScheduleGenerator extends Component { private const YEARS_IN_PAST = 1; + private const YEARS_IN_FUTURE = 5; public $selectedMonth; + public $selectedYear; + public $selectedUsers = []; + public $clearExisting = true; + public $showAdvancedOptions = false; + public $isGenerating = false; public function mount(): void @@ -32,7 +40,7 @@ public function mount(): void ->toArray(); } - public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + public function render(): Factory|View { $users = User::where('planner_id', auth()->id()) ->orderBy('name') @@ -43,7 +51,7 @@ public function render(): \Illuminate\Contracts\View\Factory|\Illuminate\Contrac return view('livewire.schedule.schedule-generator', [ 'users' => $users, 'months' => $this->getMonthNames(), - 'years' => $years + 'years' => $years, ]); } @@ -52,13 +60,13 @@ public function generate(): void $this->validate([ 'selectedUsers' => 'required|array|min:1', 'selectedMonth' => 'required|integer|min:1|max:12', - 'selectedYear' => 'required|integer|min:' . (now()->year - self::YEARS_IN_PAST) . '|max:' . (now()->year + self::YEARS_IN_FUTURE), + 'selectedYear' => 'required|integer|min:'.(now()->year - self::YEARS_IN_PAST).'|max:'.(now()->year + self::YEARS_IN_FUTURE), ]); $this->isGenerating = true; try { - $action = new GenerateScheduleForMonthAction(); + $action = new GenerateScheduleForMonthAction; $action->execute( auth()->user(), $this->selectedMonth, @@ -70,8 +78,8 @@ public function generate(): void $this->isGenerating = false; $this->dispatch('schedule-generated'); - session()->flash('success', 'Schedule generated successfully for ' . - $this->getSelectedMonthName() . ' ' . $this->selectedYear); + session()->flash('success', 'Schedule generated successfully for '. + $this->getSelectedMonthName().' '.$this->selectedYear); } catch (\Exception $e) { $this->isGenerating = false; @@ -83,7 +91,7 @@ public function generate(): void public function regenerateForDate($date): void { try { - $action = new RegenerateScheduleForDateForUsersAction(); + $action = new RegenerateScheduleForDateForUsersAction; $action->execute( auth()->user(), Carbon::parse($date), @@ -91,7 +99,7 @@ public function regenerateForDate($date): void ); $this->dispatch('schedule-generated'); - session()->flash('success', 'Schedule regenerated for ' . Carbon::parse($date)->format('M d, Y')); + session()->flash('success', 'Schedule regenerated for '.Carbon::parse($date)->format('M d, Y')); } catch (\Exception $e) { Log::error('Schedule regeneration failed', ['exception' => $e, 'date' => $date]); @@ -102,7 +110,7 @@ public function regenerateForDate($date): void public function clearMonth(): void { try { - $action = new ClearScheduleForMonthAction(); + $action = new ClearScheduleForMonthAction; $action->execute( auth()->user(), $this->selectedMonth, @@ -111,8 +119,8 @@ public function clearMonth(): void ); $this->dispatch('schedule-generated'); - session()->flash('success', 'Schedule cleared for ' . - $this->getSelectedMonthName() . ' ' . $this->selectedYear); + session()->flash('success', 'Schedule cleared for '. + $this->getSelectedMonthName().' '.$this->selectedYear); } catch (\Exception $e) { Log::error('Clear month failed', ['exception' => $e]); @@ -122,7 +130,7 @@ public function clearMonth(): void public function toggleAdvancedOptions() { - $this->showAdvancedOptions = !$this->showAdvancedOptions; + $this->showAdvancedOptions = ! $this->showAdvancedOptions; } private function getMonthNames(): array @@ -130,7 +138,7 @@ private function getMonthNames(): array return [ 1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August', - 9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December' + 9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December', ]; } diff --git a/app/Livewire/Users/UsersList.php b/app/Livewire/Users/UsersList.php index e9b3762..e641526 100644 --- a/app/Livewire/Users/UsersList.php +++ b/app/Livewire/Users/UsersList.php @@ -2,10 +2,10 @@ namespace App\Livewire\Users; -use App\Models\User; use App\Actions\User\CreateUserAction; use App\Actions\User\DeleteUserAction; use App\Actions\User\EditUserAction; +use App\Models\User; use Exception; use Illuminate\Contracts\View\View; use Livewire\Component; @@ -16,10 +16,13 @@ class UsersList extends Component use WithPagination; public bool $showCreateModal = false; + public bool $showEditModal = false; + public bool $showDeleteModal = false; public ?User $editingUser = null; + public ?User $deletingUser = null; // Form fields @@ -36,7 +39,7 @@ public function render(): View ->paginate(10); return view('livewire.users.users-list', [ - 'users' => $users + 'users' => $users, ]); } @@ -52,7 +55,7 @@ public function store(): void $this->validate(); try { - (new CreateUserAction())->execute([ + (new CreateUserAction)->execute([ 'name' => $this->name, 'planner_id' => auth()->id(), ]); @@ -62,7 +65,7 @@ public function store(): void session()->flash('success', 'User created successfully.'); } catch (Exception $e) { - session()->flash('error', 'Failed to create user: ' . $e->getMessage()); + session()->flash('error', 'Failed to create user: '.$e->getMessage()); } } @@ -79,7 +82,7 @@ public function update(): void $this->validate(); try { - (new EditUserAction())->execute($this->editingUser, ['name' => $this->name]); + (new EditUserAction)->execute($this->editingUser, ['name' => $this->name]); $this->showEditModal = false; $this->reset(['name', 'editingUser']); @@ -89,7 +92,7 @@ public function update(): void // Force component to re-render with fresh data $this->resetPage(); } catch (Exception $e) { - session()->flash('error', 'Failed to update user: ' . $e->getMessage()); + session()->flash('error', 'Failed to update user: '.$e->getMessage()); } } @@ -102,17 +105,17 @@ public function confirmDelete(User $user): void public function delete(): void { try { - (new DeleteUserAction())->execute($this->deletingUser); - + (new DeleteUserAction)->execute($this->deletingUser); + $this->showDeleteModal = false; $this->deletingUser = null; session()->flash('success', 'User deleted successfully.'); - + // Force component to re-render with fresh data $this->resetPage(); } catch (Exception $e) { - session()->flash('error', 'Failed to delete user: ' . $e->getMessage()); + session()->flash('error', 'Failed to delete user: '.$e->getMessage()); } } diff --git a/app/Models/Dish.php b/app/Models/Dish.php index a1eb1a2..da1b8ea 100755 --- a/app/Models/Dish.php +++ b/app/Models/Dish.php @@ -21,6 +21,7 @@ * @property Carbon $updated_at * @property Collection $users * @property Collection $userDishes + * * @method static create(array $data) * @method static findOrFail(int $dish_id) * @method static DishFactory factory($count = null, $state = []) diff --git a/app/Models/Planner.php b/app/Models/Planner.php index c53777e..fb18ff2 100644 --- a/app/Models/Planner.php +++ b/app/Models/Planner.php @@ -13,6 +13,7 @@ * @property int $id * @property static PlannerFactory factory($count = null, $state = []) * @property Collection $users + * * @method static first() * @method static create(array $array) */ diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php index d1e95e6..f6c15be 100644 --- a/app/Models/Schedule.php +++ b/app/Models/Schedule.php @@ -22,8 +22,9 @@ * @property Dish $dish * @property User $user * @property Carbon $date - * @property boolean $is_skipped + * @property bool $is_skipped * @property Collection $scheduledUserDishes + * * @method static create(array $array) * @method static Builder where(array|Closure|Expression|string $column, mixed $operator = null, mixed $value = null, string $boolean = 'and') * @method static ScheduleFactory factory($count = null, $state = []) @@ -38,6 +39,8 @@ class Schedule extends Model public $timestamps = false; + protected $dateFormat = 'Y-m-d'; + protected $fillable = ['planner_id', 'date', 'is_skipped']; protected $casts = [ diff --git a/app/Models/ScheduledUserDish.php b/app/Models/ScheduledUserDish.php index eb54251..8334e2a 100644 --- a/app/Models/ScheduledUserDish.php +++ b/app/Models/ScheduledUserDish.php @@ -17,6 +17,7 @@ * @property int $user_dish_id * @property UserDish $userDish * @property bool $is_skipped + * * @method static create(array $array) * @method static ScheduledUserDishFactory factory($count = null, $state = []) * @method static firstOrCreate(array $array, array $array1) @@ -29,7 +30,7 @@ class ScheduledUserDish extends Model 'schedule_id', 'user_id', 'user_dish_id', - 'is_skipped' + 'is_skipped', ]; protected $casts = [ diff --git a/app/Models/User.php b/app/Models/User.php index 6639c90..2875ea8 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -6,10 +6,10 @@ use Database\Factories\UserFactory; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; -use Illuminate\Database\Eloquent\Model; /** * @property int $id @@ -17,6 +17,7 @@ * @property string $name * @property Collection $dishes * @property Collection $userDishes + * * @method static User findOrFail(int $user_id) * @method static UserFactory factory($count = null, $state = []) * @method static create(array $array) diff --git a/app/Models/UserDish.php b/app/Models/UserDish.php index a30aab0..6981187 100644 --- a/app/Models/UserDish.php +++ b/app/Models/UserDish.php @@ -17,6 +17,7 @@ * @method static UserDish|null find(int|null $user_dish_id) * @method static create(array $array) * @method static where(string $string, int $id) + * * @property int $id * @property int $dish_id * @property int $user_id diff --git a/app/Models/UserDishRecurrence.php b/app/Models/UserDishRecurrence.php index f968d30..935ee56 100755 --- a/app/Models/UserDishRecurrence.php +++ b/app/Models/UserDishRecurrence.php @@ -36,7 +36,7 @@ public function getValue(): int return match ($this->recurrence_type) { WeeklyRecurrence::class => $this->recurrence->weekday->value, MinimumRecurrence::class => $this->recurrence->days, - default => throw new InvalidRecurrenceTypeException() + default => throw new InvalidRecurrenceTypeException }; } } diff --git a/app/Models/WeeklyRecurrence.php b/app/Models/WeeklyRecurrence.php index fa3b418..58456fb 100755 --- a/app/Models/WeeklyRecurrence.php +++ b/app/Models/WeeklyRecurrence.php @@ -12,10 +12,11 @@ /** * @property int $weekday + * * @method static create(array $array) * @method static WeeklyRecurrenceFactory factory($count = null, $state = []) */ -class WeeklyRecurrence extends Model implements RecurrenceInterface, FixedRecurrenceInterface +class WeeklyRecurrence extends Model implements FixedRecurrenceInterface, RecurrenceInterface { /** @use HasFactory */ use HasFactory; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0bbbb1e..8b1ea1e 100755 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -16,7 +16,6 @@ use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as BaseHandler; use Illuminate\Support\Facades\Gate; -use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; use Throwable; @@ -25,7 +24,8 @@ class AppServiceProvider extends ServiceProvider public function register(): void { $this->app->bind(ExceptionHandler::class, function ($app) { - return new class($app) extends BaseHandler { + return new class($app) extends BaseHandler + { public function render($request, Throwable $e) { // Handle specific custom exception diff --git a/app/Services/OutputService.php b/app/Services/OutputService.php index 2e7882e..430f2e1 100644 --- a/app/Services/OutputService.php +++ b/app/Services/OutputService.php @@ -2,7 +2,6 @@ namespace App\Services; - class OutputService { public function response(bool $success = true, ?array $payload = null, array|string|null $errors = null): array diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 38b258d..fc94ae6 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -1,5 +1,7 @@ [ 'planners' => [ 'driver' => 'eloquent', - 'model' => App\Models\Planner::class, + 'model' => Planner::class, ], // 'users' => [ diff --git a/config/sanctum.php b/config/sanctum.php index 764a82f..b660703 100644 --- a/config/sanctum.php +++ b/config/sanctum.php @@ -1,5 +1,8 @@ [ - 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, - 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, - 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, + 'authenticate_session' => AuthenticateSession::class, + 'encrypt_cookies' => EncryptCookies::class, + 'validate_csrf_token' => ValidateCsrfToken::class, ], ]; diff --git a/database/factories/UserDishFactory.php b/database/factories/UserDishFactory.php index 7c235ef..00fcbd8 100644 --- a/database/factories/UserDishFactory.php +++ b/database/factories/UserDishFactory.php @@ -3,8 +3,8 @@ namespace Database\Factories; use App\Models\Dish; -use App\Models\UserDish; use App\Models\User; +use App\Models\UserDish; use Illuminate\Database\Eloquent\Factories\Factory; /** diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 3a08996..b1502d2 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,7 +2,6 @@ namespace Database\Seeders; -use App\Models\User; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; diff --git a/database/seeders/DevelopmentSeeder.php b/database/seeders/DevelopmentSeeder.php index 0b470d8..c7f06cc 100644 --- a/database/seeders/DevelopmentSeeder.php +++ b/database/seeders/DevelopmentSeeder.php @@ -73,4 +73,4 @@ public function run(): void $this->command->info('Development data seeded successfully!'); $this->command->info('Login credentials: myrmidex@myrmidex.net / Password'); } -} \ No newline at end of file +} diff --git a/database/seeders/PlannersSeeder.php b/database/seeders/PlannersSeeder.php index 2d98cc8..f46a205 100644 --- a/database/seeders/PlannersSeeder.php +++ b/database/seeders/PlannersSeeder.php @@ -14,7 +14,7 @@ public function run(): void [ 'name' => 'Admin', 'email' => 'admin@test.com', - 'password' => 'password' + 'password' => 'password', ], ])->each(fn (array $data) => Planner::create([ 'name' => $data['name'], diff --git a/database/seeders/ScheduleSeeder.php b/database/seeders/ScheduleSeeder.php index 82652c6..2864378 100755 --- a/database/seeders/ScheduleSeeder.php +++ b/database/seeders/ScheduleSeeder.php @@ -41,17 +41,16 @@ private function createScheduleForPeriod(CarbonPeriod $period): void $planner = Planner::all()->first() ?? Planner::factory()->create(); collect($period) - ->each(fn (Carbon $date) => - User::query() - ->inRandomOrder() - ->get() - ->each(fn (User $user) => (new CreateScheduledUserDishAction()) - ->execute( - planner: $planner, - schedule: resolve(ScheduleRepository::class)->findOrCreate($planner, $date), - userDish: $user->userDishes->random(), - ) + ->each(fn (Carbon $date) => User::query() + ->inRandomOrder() + ->get() + ->each(fn (User $user) => (new CreateScheduledUserDishAction) + ->execute( + planner: $planner, + schedule: resolve(ScheduleRepository::class)->findOrCreate($planner, $date), + userDish: $user->userDishes->random(), ) + ) ); } } diff --git a/database/seeders/UsersSeeder.php b/database/seeders/UsersSeeder.php index 2217a9a..ef9f08a 100644 --- a/database/seeders/UsersSeeder.php +++ b/database/seeders/UsersSeeder.php @@ -16,7 +16,6 @@ public function run(): void ->each(fn (string $name) => User::factory()->create([ 'planner_id' => $planner->id, 'name' => $name, - ])) - ; + ])); } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..9c757af --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,2839 @@ +parameters: + ignoreErrors: + - + message: '#^Method App\\Actions\\User\\CreateUserAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Actions/User/CreateUserAction.php + + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: app/Actions/User/CreateUserAction.php + + - + message: '#^Method App\\Actions\\User\\EditUserAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Actions/User/EditUserAction.php + + - + message: '#^Method App\\Http\\Controllers\\Api\\ApiController\:\:error\(\) has parameter \$errors with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Controllers/Api/ApiController.php + + - + message: '#^Method App\\Http\\Controllers\\Api\\ApiController\:\:response\(\) has parameter \$errors with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Controllers/Api/ApiController.php + + - + message: '#^Method App\\Http\\Controllers\\Api\\ApiController\:\:response\(\) has parameter \$payload with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Controllers/Api/ApiController.php + + - + message: '#^Method App\\Http\\Controllers\\Api\\ApiController\:\:success\(\) has parameter \$payload with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Controllers/Api/ApiController.php + + - + message: '#^Method App\\Http\\Controllers\\Auth\\LoginController\:\:login\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Http/Controllers/Auth/LoginController.php + + - + message: '#^Method App\\Http\\Controllers\\Auth\\LoginController\:\:logout\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Http/Controllers/Auth/LoginController.php + + - + message: '#^Method App\\Http\\Controllers\\Auth\\LoginController\:\:showLoginForm\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Http/Controllers/Auth/LoginController.php + + - + message: '#^Method App\\Http\\Controllers\\Auth\\RegisterController\:\:register\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Http/Controllers/Auth/RegisterController.php + + - + message: '#^Method App\\Http\\Controllers\\Auth\\RegisterController\:\:showRegistrationForm\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Http/Controllers/Auth/RegisterController.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\MinimalScheduleResource\:\:\$date\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/MinimalScheduleResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\MinimalScheduleResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/MinimalScheduleResource.php + + - + message: '#^Method App\\Http\\Resources\\MinimalScheduleResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/MinimalScheduleResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\MinimalScheduledUserDishResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/MinimalScheduledUserDishResource.php + + - + message: '#^Method App\\Http\\Resources\\MinimalScheduledUserDishResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/MinimalScheduledUserDishResource.php + + - + message: '#^Using nullsafe property access on non\-nullable type App\\Models\\UserDish\. Use \-\> instead\.$#' + identifier: nullsafe.neverNull + count: 2 + path: app/Http/Resources/MinimalScheduledUserDishResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\ScheduledUserDishResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/ScheduledUserDishResource.php + + - + message: '#^Method App\\Http\\Resources\\ScheduledUserDishResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/ScheduledUserDishResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserDishResource\:\:\$dish\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserDishResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserDishResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserDishResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserDishResource\:\:\$recurrences\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserDishResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserDishResource\:\:\$user\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserDishResource.php + + - + message: '#^Method App\\Http\\Resources\\UserDishResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/UserDishResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserResource\:\:\$name\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserResource.php + + - + message: '#^Method App\\Http\\Resources\\UserResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/UserResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserWithDishesResource\:\:\$dishes\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserWithDishesResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserWithDishesResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserWithDishesResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserWithDishesResource\:\:\$name\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserWithDishesResource.php + + - + message: '#^Method App\\Http\\Resources\\UserWithDishesResource\:\:mapDishes\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/UserWithDishesResource.php + + - + message: '#^Method App\\Http\\Resources\\UserWithDishesResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/UserWithDishesResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserWithUserDishesResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserWithUserDishesResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserWithUserDishesResource\:\:\$name\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserWithUserDishesResource.php + + - + message: '#^Access to an undefined property App\\Http\\Resources\\UserWithUserDishesResource\:\:\$userDishes\.$#' + identifier: property.notFound + count: 1 + path: app/Http/Resources/UserWithUserDishesResource.php + + - + message: '#^Method App\\Http\\Resources\\UserWithUserDishesResource\:\:mapDishes\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/UserWithUserDishesResource.php + + - + message: '#^Method App\\Http\\Resources\\UserWithUserDishesResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Http/Resources/UserWithUserDishesResource.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:cancel\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:confirmDelete\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:create\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:delete\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:edit\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:render\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:store\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Dishes\\DishesList\:\:update\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$deletingDish has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$editingDish has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$name has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$rules has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$selectedUsers has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$showCreateModal has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$showDeleteModal has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Property App\\Livewire\\Dishes\\DishesList\:\:\$showEditModal has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Dishes/DishesList.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:editDish\(\) has parameter \$date with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:editDish\(\) has parameter \$userId with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:openAddDishModal\(\) has parameter \$date with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:regenerateForUserDate\(\) has parameter \$date with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:regenerateForUserDate\(\) has parameter \$userId with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:removeDish\(\) has parameter \$date with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:removeDish\(\) has parameter \$userId with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:skipDay\(\) has parameter \$date with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleCalendar\:\:skipDay\(\) has parameter \$userId with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$addAvailableDishes has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$addAvailableUsers has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$addDate has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$addSelectedDishId has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$addUserIds has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$availableDishes has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$calendarDays has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$currentMonth has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$currentYear has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$editDate has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$editUserId has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$listeners has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$regenerateDate has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$regenerateUserId has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$selectedDishId has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$showAddDishModal has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$showEditDishModal has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleCalendar\:\:\$showRegenerateModal has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: app/Livewire/Schedule/ScheduleCalendar.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleGenerator\:\:getMonthNames\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleGenerator\:\:regenerateForDate\(\) has parameter \$date with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Method App\\Livewire\\Schedule\\ScheduleGenerator\:\:toggleAdvancedOptions\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleGenerator\:\:\$clearExisting has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleGenerator\:\:\$isGenerating has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleGenerator\:\:\$selectedMonth has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleGenerator\:\:\$selectedUsers has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleGenerator\:\:\$selectedYear has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Schedule\\ScheduleGenerator\:\:\$showAdvancedOptions has no type specified\.$#' + identifier: missingType.property + count: 1 + path: app/Livewire/Schedule/ScheduleGenerator.php + + - + message: '#^Property App\\Livewire\\Users\\UsersList\:\:\$rules type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Livewire/Users/UsersList.php + + - + message: '#^Class App\\Models\\Dish has PHPDoc tag @method for method create\(\) parameter \#1 \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/Dish.php + + - + message: '#^Method App\\Models\\Dish\:\:recurrences\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough does not specify its types\: TRelatedModel, TIntermediateModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Dish.php + + - + message: '#^Method App\\Models\\Dish\:\:userDishes\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Dish.php + + - + message: '#^Method App\\Models\\Dish\:\:users\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany does not specify its types\: TRelatedModel, TDeclaringModel, TPivotModel, TAccessor \(2\-4 required\)$#' + identifier: missingType.generics + count: 1 + path: app/Models/Dish.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\Dish\:\:\$userDishes contains generic class Illuminate\\Support\\Collection but does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: app/Models/Dish.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\Dish\:\:\$users contains generic class Illuminate\\Support\\Collection but does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: app/Models/Dish.php + + - + message: '#^Method App\\Models\\MinimumRecurrence\:\:recurrence\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\MorphOne does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/MinimumRecurrence.php + + - + message: '#^Class App\\Models\\Planner has PHPDoc tag @method for method create\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/Planner.php + + - + message: '#^Class App\\Models\\Planner uses generic trait Illuminate\\Database\\Eloquent\\Factories\\HasFactory but does not specify its types\: TFactory$#' + identifier: missingType.generics + count: 1 + path: app/Models/Planner.php + + - + message: '#^Method App\\Models\\Planner\:\:schedules\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Planner.php + + - + message: '#^Method App\\Models\\Planner\:\:users\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Planner.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\Planner\:\:\$users contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Planner.php + + - + message: '#^PHPDoc tag @property has invalid value \(static PlannerFactory factory\(\$count \= null, \$state \= \[\]\)\)\: Unexpected token "PlannerFactory", expected variable at offset 45 on line 3$#' + identifier: phpDoc.parseError + count: 1 + path: app/Models/Planner.php + + - + message: '#^Class App\\Models\\Schedule has PHPDoc tag @method for method create\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/Schedule.php + + - + message: '#^Class App\\Models\\Schedule has PHPDoc tag @method for method firstOrCreate\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/Schedule.php + + - + message: '#^Class App\\Models\\Schedule has PHPDoc tag @method for method where\(\) parameter \#1 \$column with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/Schedule.php + + - + message: '#^Method App\\Models\\Schedule\:\:scheduledUserDishes\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Schedule.php + + - + message: '#^PHPDoc tag @method for method App\\Models\\Schedule\:\:where\(\) parameter \#1 \$column contains generic class Illuminate\\Database\\Query\\Expression but does not specify its types\: TValue$#' + identifier: missingType.generics + count: 1 + path: app/Models/Schedule.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\Schedule\:\:\$scheduledUserDishes contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/Schedule.php + + - + message: '#^Class App\\Models\\ScheduledUserDish has PHPDoc tag @method for method create\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Class App\\Models\\ScheduledUserDish has PHPDoc tag @method for method firstOrCreate\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Class App\\Models\\ScheduledUserDish has PHPDoc tag @method for method firstOrCreate\(\) parameter \#2 \$array1 with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Class App\\Models\\ScheduledUserDish uses generic trait Illuminate\\Database\\Eloquent\\Factories\\HasFactory but does not specify its types\: TFactory$#' + identifier: missingType.generics + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Method App\\Models\\ScheduledUserDish\:\:schedule\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Method App\\Models\\ScheduledUserDish\:\:scopeForUser\(\) has parameter \$query with generic class Illuminate\\Database\\Eloquent\\Builder but does not specify its types\: TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Method App\\Models\\ScheduledUserDish\:\:scopeForUser\(\) return type with generic class Illuminate\\Database\\Eloquent\\Builder does not specify its types\: TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Method App\\Models\\ScheduledUserDish\:\:user\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Method App\\Models\\ScheduledUserDish\:\:userDish\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/ScheduledUserDish.php + + - + message: '#^Class App\\Models\\User has PHPDoc tag @method for method create\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/User.php + + - + message: '#^Method App\\Models\\User\:\:dishes\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany does not specify its types\: TRelatedModel, TDeclaringModel, TPivotModel, TAccessor \(2\-4 required\)$#' + identifier: missingType.generics + count: 1 + path: app/Models/User.php + + - + message: '#^Method App\\Models\\User\:\:recurrences\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasManyThrough does not specify its types\: TRelatedModel, TIntermediateModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/User.php + + - + message: '#^Method App\\Models\\User\:\:userDishes\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/User.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\User\:\:\$dishes contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/User.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\User\:\:\$userDishes contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/User.php + + - + message: '#^Class App\\Models\\UserDish has PHPDoc tag @method for method create\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/UserDish.php + + - + message: '#^Class App\\Models\\UserDish uses generic trait Illuminate\\Database\\Eloquent\\Factories\\HasFactory but does not specify its types\: TFactory$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^Method App\\Models\\UserDish\:\:dish\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^Method App\\Models\\UserDish\:\:fixedRecurrences\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^Method App\\Models\\UserDish\:\:recurrences\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\HasMany does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^Method App\\Models\\UserDish\:\:user\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\UserDish\:\:\$fixedRecurrences contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^PHPDoc tag @property for property App\\Models\\UserDish\:\:\$recurrences contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDish.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$days\.$#' + identifier: property.notFound + count: 1 + path: app/Models/UserDishRecurrence.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$weekday\.$#' + identifier: property.notFound + count: 1 + path: app/Models/UserDishRecurrence.php + + - + message: '#^Method App\\Models\\UserDishRecurrence\:\:dishUser\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\BelongsTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDishRecurrence.php + + - + message: '#^Method App\\Models\\UserDishRecurrence\:\:recurrence\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\MorphTo does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/UserDishRecurrence.php + + - + message: '#^Class App\\Models\\WeeklyRecurrence has PHPDoc tag @method for method create\(\) parameter \#1 \$array with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Models/WeeklyRecurrence.php + + - + message: '#^Method App\\Models\\WeeklyRecurrence\:\:recurrence\(\) return type with generic class Illuminate\\Database\\Eloquent\\Relations\\MorphOne does not specify its types\: TRelatedModel, TDeclaringModel$#' + identifier: missingType.generics + count: 1 + path: app/Models/WeeklyRecurrence.php + + - + message: '#^Expression on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.expr + count: 1 + path: app/Providers/AppServiceProvider.php + + - + message: '#^Method App\\Services\\OutputService\:\:error\(\) has parameter \$errors with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method App\\Services\\OutputService\:\:error\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method App\\Services\\OutputService\:\:response\(\) has parameter \$errors with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method App\\Services\\OutputService\:\:response\(\) has parameter \$payload with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method App\\Services\\OutputService\:\:response\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method App\\Services\\OutputService\:\:success\(\) has parameter \$payload with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method App\\Services\\OutputService\:\:success\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: app/Services/OutputService.php + + - + message: '#^Method DishPlanner\\Auth\\Controllers\\PlannerAuthController\:\:register\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: src/DishPlanner/Auth/Controllers/PlannerAuthController.php + + - + message: '#^Method DishPlanner\\Dish\\Actions\\AddUsersToDishAction\:\:execute\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Actions/AddUsersToDishAction.php + + - + message: '#^Method DishPlanner\\Dish\\Actions\\CreateDishAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Actions/CreateDishAction.php + + - + message: '#^Method DishPlanner\\Dish\\Actions\\RemoveUsersFromDishAction\:\:execute\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Actions/RemoveUsersFromDishAction.php + + - + message: '#^Method DishPlanner\\Dish\\Actions\\SyncUsersAction\:\:execute\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Actions/SyncUsersAction.php + + - + message: '#^Method DishPlanner\\Dish\\Actions\\UpdateDishAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Actions/UpdateDishAction.php + + - + message: '#^Property DishPlanner\\Dish\\Exceptions\\InvalidDishException\:\:\$code has no type specified\.$#' + identifier: missingType.property + count: 1 + path: src/DishPlanner/Dish/Exceptions/InvalidDishException.php + + - + message: '#^Method DishPlanner\\Dish\\Repositories\\DishRepository\:\:getRandomDish\(\) should return App\\Models\\Dish but returns \(Illuminate\\Database\\Eloquent\\Model&object\{pivot\: Illuminate\\Database\\Eloquent\\Relations\\Pivot\}\)\|null\.$#' + identifier: return.type + count: 1 + path: src/DishPlanner/Dish/Repositories/DishRepository.php + + - + message: '#^Method DishPlanner\\Dish\\Requests\\AddUsersToDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Requests/AddUsersToDishRequest.php + + - + message: '#^Method DishPlanner\\Dish\\Requests\\RemoveUsersFromDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Requests/RemoveUsersFromDishRequest.php + + - + message: '#^Method DishPlanner\\Dish\\Requests\\StoreDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Requests/StoreDishRequest.php + + - + message: '#^Method DishPlanner\\Dish\\Requests\\SyncUsersRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Requests/SyncUsersRequest.php + + - + message: '#^Method DishPlanner\\Dish\\Requests\\UpdateDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Requests/UpdateDishRequest.php + + - + message: '#^Access to an undefined property DishPlanner\\Dish\\Resources\\DishResource\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Dish/Resources/DishResource.php + + - + message: '#^Access to an undefined property DishPlanner\\Dish\\Resources\\DishResource\:\:\$name\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Dish/Resources/DishResource.php + + - + message: '#^Access to an undefined property DishPlanner\\Dish\\Resources\\DishResource\:\:\$planner_id\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Dish/Resources/DishResource.php + + - + message: '#^Access to an undefined property DishPlanner\\Dish\\Resources\\DishResource\:\:\$userDishes\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Dish/Resources/DishResource.php + + - + message: '#^Method DishPlanner\\Dish\\Resources\\DishResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Dish/Resources/DishResource.php + + - + message: '#^Method DishPlanner\\Planner\\Actions\\CreatePlannerAction\:\:execute\(\) has parameter \$data with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: src/DishPlanner/Planner/Actions/CreatePlannerAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\ClearScheduleForMonthAction\:\:execute\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/ClearScheduleForMonthAction.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:map\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: \(App\\Models\\User\|null\), Closure\(App\\Models\\ScheduledUserDish\)\: \(App\\Models\\User\|null\) given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php + + - + message: '#^Using nullsafe property access on non\-nullable type App\\Models\\UserDish\. Use \-\> instead\.$#' + identifier: nullsafe.neverNull + count: 1 + path: src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php + + - + message: '#^Unable to resolve the template type TKey in call to function collect$#' + identifier: argument.templateType + count: 1 + path: src/DishPlanner/Schedule/Actions/DraftScheduleForPeriodAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\GenerateScheduleForMonthAction\:\:clearExistingSchedules\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\GenerateScheduleForMonthAction\:\:execute\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\GenerateScheduleForMonthAction\:\:generateSchedulesForPeriod\(\) has parameter \$userDishesMap with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\GenerateScheduleForMonthAction\:\:generateSchedulesForPeriod\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\GenerateScheduleForMonthAction\:\:loadUserDishes\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\GenerateScheduleForMonthAction\:\:loadUserDishes\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:each\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: mixed, Closure\(App\\Models\\User\)\: App\\Models\\ScheduledUserDish given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/Schedule/Actions/RegenerateScheduleDayAction.php + + - + message: '#^Parameter \$userDish of method DishPlanner\\ScheduledUserDish\\Actions\\CreateScheduledUserDishAction\:\:execute\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 2 + path: src/DishPlanner/Schedule/Actions/RegenerateScheduleDayForUserAction.php + + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: src/DishPlanner/Schedule/Actions/RegenerateScheduleDayForUserAction.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Schedule/Actions/RegenerateScheduleForDateForUsersAction.php + + - + message: '#^Method DishPlanner\\Schedule\\Actions\\RegenerateScheduleForDateForUsersAction\:\:execute\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Actions/RegenerateScheduleForDateForUsersAction.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:each\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: mixed, Closure\(App\\Models\\ScheduledUserDish\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/Schedule/Actions/UpdateScheduleAction.php + + - + message: '#^Access to an undefined property App\\Models\\UserDish\|Illuminate\\Database\\Eloquent\\Collection\\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php + + - + message: '#^Access to an undefined property App\\Models\\UserDish\|Illuminate\\Database\\Eloquent\\Collection\\:\:\$user\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php + + - + message: '#^Access to an undefined property App\\Models\\User\|Illuminate\\Database\\Eloquent\\Collection\\:\:\$id\.$#' + identifier: property.notFound + count: 3 + path: src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php + + - + message: '#^Call to an undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany\:\:forUser\(\)\.$#' + identifier: method.notFound + count: 1 + path: src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php + + - + message: '#^Method DishPlanner\\Schedule\\Requests\\CreateScheduleRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Requests/CreateScheduleRequest.php + + - + message: '#^Method DishPlanner\\Schedule\\Requests\\GenerateScheduleRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Requests/GenerateScheduleRequest.php + + - + message: '#^Method DishPlanner\\Schedule\\Requests\\ScheduleUserDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Requests/ScheduleUserDishRequest.php + + - + message: '#^Method DishPlanner\\Schedule\\Requests\\UpdateScheduleRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Requests/UpdateScheduleRequest.php + + - + message: '#^Method DishPlanner\\Schedule\\Resources\\ScheduleResource\:\:scheduledUserDishes\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Resources/ScheduleResource.php + + - + message: '#^Method DishPlanner\\Schedule\\Resources\\ScheduleResource\:\:toArray\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Resources/ScheduleResource.php + + - + message: '#^PHPDoc tag @property for property DishPlanner\\Schedule\\Resources\\ScheduleResource\:\:\$scheduledUserDishes contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/Schedule/Resources/ScheduleResource.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:map\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: array\{id\: int, user\: array\{id\: int, name\: string\}, skipped\: bool, user_dish\: App\\Http\\Resources\\UserDishResource\}, Closure\(App\\Models\\ScheduledUserDish\)\: array\{id\: int, user\: array\{id\: int, name\: string\}, skipped\: bool, user_dish\: App\\Http\\Resources\\UserDishResource\} given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/Schedule/Resources/ScheduleResource.php + + - + message: '#^Method DishPlanner\\Schedule\\Services\\ScheduleCalendarService\:\:buildCalendarDays\(\) has parameter \$schedules with generic class Illuminate\\Support\\Collection but does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/Schedule/Services/ScheduleCalendarService.php + + - + message: '#^Method DishPlanner\\Schedule\\Services\\ScheduleCalendarService\:\:buildCalendarDays\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Services/ScheduleCalendarService.php + + - + message: '#^Method DishPlanner\\Schedule\\Services\\ScheduleCalendarService\:\:getCalendarDays\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/Schedule/Services/ScheduleCalendarService.php + + - + message: '#^Method DishPlanner\\Schedule\\Services\\ScheduleCalendarService\:\:loadSchedulesForMonth\(\) return type with generic class Illuminate\\Support\\Collection does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/Schedule/Services/ScheduleCalendarService.php + + - + message: '#^Using nullsafe property access "\?\-\>scheduledUserDishes" on left side of \?\? is unnecessary\. Use \-\> instead\.$#' + identifier: nullsafe.neverNull + count: 1 + path: src/DishPlanner/Schedule/Services/ScheduleCalendarService.php + + - + message: '#^Method DishPlanner\\ScheduledUserDish\\Requests\\UpdateScheduledUserDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/ScheduledUserDish/Requests/UpdateScheduledUserDishRequest.php + + - + message: '#^Method DishPlanner\\User\\Requests\\CreateUserRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/User/Requests/CreateUserRequest.php + + - + message: '#^Method DishPlanner\\User\\Requests\\UpdateUserRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/User/Requests/UpdateUserRequest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$recurrence\.$#' + identifier: property.notFound + count: 2 + path: src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:each\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: mixed, Closure\(App\\Models\\UserDishRecurrence\)\: \(bool\|null\) given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:filter\(\) expects \(callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: bool\)\|null, Closure\(App\\Models\\UserDishRecurrence\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php + + - + message: '#^Method DishPlanner\\UserDish\\Actions\\CreateUserDishAction\:\:addRecurrences\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Actions/CreateUserDishAction.php + + - + message: '#^Method DishPlanner\\UserDish\\Actions\\CreateUserDishAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Actions/CreateUserDishAction.php + + - + message: '#^Method DishPlanner\\UserDish\\Actions\\SyncRecurrencesForUserDishAction\:\:execute\(\) has parameter \$recurrences with generic class Illuminate\\Support\\Collection but does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/UserDish/Actions/SyncRecurrencesForUserDishAction.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Builder\\:\:each\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\)\: mixed, Closure\(App\\Models\\UserDishRecurrence\)\: void given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/UserDish/Actions/SyncRecurrencesForUserDishAction.php + + - + message: '#^Method DishPlanner\\UserDish\\Actions\\UpdateFixedRecurrenceAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Actions/UpdateFixedRecurrenceAction.php + + - + message: '#^Method DishPlanner\\UserDish\\Actions\\UpdateMinimumRecurrenceAction\:\:execute\(\) has parameter \$data with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Actions/UpdateMinimumRecurrenceAction.php + + - + message: '#^Method DishPlanner\\UserDish\\Controllers\\ListUserDishesController\:\:__invoke\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: src/DishPlanner/UserDish/Controllers/ListUserDishesController.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$recurrence\.$#' + identifier: property.notFound + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Method DishPlanner\\UserDish\\Repositories\\UserDishRepository\:\:findCandidatesForDate\(\) return type with generic class Illuminate\\Support\\Collection does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Method DishPlanner\\UserDish\\Repositories\\UserDishRepository\:\:findInterferingUserDishes\(\) return type with generic class Illuminate\\Database\\Eloquent\\Collection does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Method DishPlanner\\UserDish\\Repositories\\UserDishRepository\:\:getAllForPlanner\(\) return type with generic class Illuminate\\Database\\Eloquent\\Collection does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:map\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: App\\Models\\UserDish, Closure\(App\\Models\\ScheduledUserDish\)\: App\\Models\\UserDish given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:filter\(\) expects \(callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: bool\)\|null, Closure\(App\\Models\\ScheduledUserDish\)\: bool given\.$#' + identifier: argument.type + count: 3 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:filter\(\) expects \(callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: bool\)\|null, Closure\(App\\Models\\UserDish\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:reject\(\) expects bool\|\(callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: bool\)\|Illuminate\\Database\\Eloquent\\Model, Closure\(App\\Models\\UserDish\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: src/DishPlanner/UserDish/Repositories/UserDishRepository.php + + - + message: '#^Method DishPlanner\\UserDish\\Requests\\CreateUserDishRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Requests/CreateUserDishRequest.php + + - + message: '#^Method DishPlanner\\UserDish\\Requests\\StoreUserDishRecurrenceRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Requests/StoreUserDishRecurrenceRequest.php + + - + message: '#^Method DishPlanner\\UserDish\\Requests\\UpdateUserDishFixedRecurrenceRequest\:\:rules\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: src/DishPlanner/UserDish/Requests/UpdateUserDishFixedRecurrenceRequest.php + + - + message: '#^Property Tests\\Browser\\Auth\\LoginTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Auth/LoginTest.php + + - + message: '#^Property Tests\\Browser\\Auth\\LoginTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Auth/LoginTest.php + + - + message: '#^Property Tests\\Browser\\Auth\\LoginTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Auth/LoginTest.php + + - + message: '#^Method Tests\\Browser\\Components\\DishModal\:\:selectUsers\(\) has parameter \$userIds with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: tests/Browser/Components/DishModal.php + + - + message: '#^Call to an undefined method Laravel\\Dusk\\Browser\:\:openCreateModal\(\)\.$#' + identifier: method.notFound + count: 1 + path: tests/Browser/Dishes/CreateDishFormValidationTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishFormValidationTest\:\:\$createDishFormValidationTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishFormValidationTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishFormValidationTest\:\:\$createDishFormValidationTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishFormValidationTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishFormValidationTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishFormValidationTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishFormValidationTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishFormValidationTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishFormValidationTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishFormValidationTest.php + + - + message: '#^Call to an undefined method Laravel\\Dusk\\Browser\:\:openCreateModal\(\)\.$#' + identifier: method.notFound + count: 1 + path: tests/Browser/Dishes/CreateDishSuccessTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishSuccessTest\:\:\$createDishSuccessTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishSuccessTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishSuccessTest\:\:\$createDishSuccessTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishSuccessTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishSuccessTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishSuccessTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishSuccessTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishSuccessTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishSuccessTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishSuccessTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishTest\:\:\$createDishTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishTest\:\:\$createDishTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\CreateDishTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/CreateDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DeleteDishTest\:\:\$deleteDishTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DeleteDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DeleteDishTest\:\:\$deleteDishTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DeleteDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DeleteDishTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DeleteDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DeleteDishTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DeleteDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DeleteDishTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DeleteDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DishDeletionSafetyTest\:\:\$dishDeletionSafetyTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DishDeletionSafetyTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DishDeletionSafetyTest\:\:\$dishDeletionSafetyTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DishDeletionSafetyTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DishDeletionSafetyTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DishDeletionSafetyTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DishDeletionSafetyTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DishDeletionSafetyTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\DishDeletionSafetyTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/DishDeletionSafetyTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\EditDishTest\:\:\$editDishTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/EditDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\EditDishTest\:\:\$editDishTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/EditDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\EditDishTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/EditDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\EditDishTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/EditDishTest.php + + - + message: '#^Property Tests\\Browser\\Dishes\\EditDishTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Dishes/EditDishTest.php + + - + message: '#^Method Tests\\Browser\\Pages\\SchedulePage\:\:elements\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: tests/Browser/Pages/SchedulePage.php + + - + message: '#^Parameter \#2 \$value of method Laravel\\Dusk\\Browser\:\:select\(\) expects array\|string\|null, int given\.$#' + identifier: argument.type + count: 2 + path: tests/Browser/Pages/SchedulePage.php + + - + message: '#^Method Tests\\Browser\\RedirectTest\:\:test_login_page_loads\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: tests/Browser/RedirectTest.php + + - + message: '#^Method Tests\\Browser\\RedirectTest\:\:test_unauthenticated_redirects_to_login\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: tests/Browser/RedirectTest.php + + - + message: '#^Call to an undefined method Laravel\\Dusk\\Browser\:\:clickGenerate\(\)\.$#' + identifier: method.notFound + count: 3 + path: tests/Browser/Schedule/GenerateScheduleTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\GenerateScheduleTest\:\:\$dish has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/GenerateScheduleTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\GenerateScheduleTest\:\:\$email has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/GenerateScheduleTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\GenerateScheduleTest\:\:\$password has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/GenerateScheduleTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\GenerateScheduleTest\:\:\$planner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/GenerateScheduleTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\GenerateScheduleTest\:\:\$user has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/GenerateScheduleTest.php + + - + message: '#^Call to an undefined method Laravel\\Dusk\\Browser\:\:goToNextMonth\(\)\.$#' + identifier: method.notFound + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Call to an undefined method Laravel\\Dusk\\Browser\:\:goToPreviousMonth\(\)\.$#' + identifier: method.notFound + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\SchedulePageTest\:\:\$schedulePageTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\SchedulePageTest\:\:\$schedulePageTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\SchedulePageTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\SchedulePageTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Property Tests\\Browser\\Schedule\\SchedulePageTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Schedule/SchedulePageTest.php + + - + message: '#^Call to an undefined method Laravel\\Dusk\\Browser\:\:openCreateModal\(\)\.$#' + identifier: method.notFound + count: 4 + path: tests/Browser/Users/CreateUserTest.php + + - + message: '#^Property Tests\\Browser\\Users\\CreateUserTest\:\:\$createUserTestEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Users/CreateUserTest.php + + - + message: '#^Property Tests\\Browser\\Users\\CreateUserTest\:\:\$createUserTestPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Users/CreateUserTest.php + + - + message: '#^Property Tests\\Browser\\Users\\CreateUserTest\:\:\$testEmail has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Users/CreateUserTest.php + + - + message: '#^Property Tests\\Browser\\Users\\CreateUserTest\:\:\$testPassword has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Users/CreateUserTest.php + + - + message: '#^Property Tests\\Browser\\Users\\CreateUserTest\:\:\$testPlanner has no type specified\.$#' + identifier: missingType.property + count: 1 + path: tests/Browser/Users/CreateUserTest.php + + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertNotNull\(\) with string will always evaluate to true\.$#' + identifier: method.alreadyNarrowedType + count: 1 + path: tests/Feature/AuthenticationTest.php + + - + message: '#^Parameter \#1 \$user of method Illuminate\\Foundation\\Testing\\TestCase\:\:actingAs\(\) expects Illuminate\\Contracts\\Auth\\Authenticatable, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/AuthenticationTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\AddUsersToDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/AddUsersToDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/AddUsersToDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/AddUsersToDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\AddUsersToDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/AddUsersToDishTest.php + + - + message: '#^Called ''first'' on Laravel collection, but could have been retrieved as a query\.$#' + identifier: larastan.noUnnecessaryCollectionCall + count: 1 + path: tests/Feature/Dish/CreateDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\CreateDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/CreateDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\CreateDishTest\:\:invalidNameValues\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: tests/Feature/Dish/CreateDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\CreateDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/CreateDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\DeleteDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/DeleteDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/DeleteDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\DeleteDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/DeleteDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\ListDishesTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/ListDishesTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/ListDishesTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\ListDishesTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/ListDishesTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\RemoveUsersFromDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/RemoveUsersFromDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/RemoveUsersFromDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/RemoveUsersFromDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\RemoveUsersFromDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/RemoveUsersFromDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\ShowDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/ShowDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/ShowDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\ShowDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/ShowDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\SyncUsersForDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/SyncUsersForDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/SyncUsersForDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/SyncUsersForDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\SyncUsersForDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/SyncUsersForDishTest.php + + - + message: '#^Method Tests\\Feature\\Dish\\UpdateDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Dish/UpdateDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Dish/UpdateDishTest.php + + - + message: '#^Property Tests\\Feature\\Dish\\UpdateDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Dish/UpdateDishTest.php + + - + message: '#^Method Tests\\Feature\\RegistrationTest\:\:test_new_users_can_register\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: tests/Feature/RegistrationTest.php + + - + message: '#^Method Tests\\Feature\\RegistrationTest\:\:test_registration_fails_with_existing_email\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: tests/Feature/RegistrationTest.php + + - + message: '#^Method Tests\\Feature\\RegistrationTest\:\:test_registration_fails_with_password_mismatch\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: tests/Feature/RegistrationTest.php + + - + message: '#^Method Tests\\Feature\\RegistrationTest\:\:test_registration_screen_can_be_rendered\(\) has no return type specified\.$#' + identifier: missingType.return + count: 1 + path: tests/Feature/RegistrationTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 4 + path: tests/Feature/Schedule/GenerateScheduleTest.php + + - + message: '#^Method Tests\\Feature\\Schedule\\GenerateScheduleTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Schedule/GenerateScheduleTest.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:map\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: array\{user_dish_id\: int\}, Closure\(App\\Models\\ScheduledUserDish\)\: array\{user_dish_id\: int\} given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/GenerateScheduleTest.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:filter\(\) expects \(callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: bool\)\|null, Closure\(App\\Models\\ScheduledUserDish\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/GenerateScheduleTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/GenerateScheduleTest.php + + - + message: '#^Property Tests\\Feature\\Schedule\\GenerateScheduleTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Schedule/GenerateScheduleTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 2 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$user\.$#' + identifier: property.notFound + count: 2 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Method Tests\\Feature\\Schedule\\ListScheduleTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Property Tests\\Feature\\Schedule\\ListScheduleTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Schedule/ListScheduleTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$date\.$#' + identifier: property.notFound + count: 2 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Method Tests\\Feature\\Schedule\\ReadScheduleTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Property Tests\\Feature\\Schedule\\ReadScheduleTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Unable to resolve the template type TKey in call to function collect$#' + identifier: argument.templateType + count: 1 + path: tests/Feature/Schedule/ReadScheduleTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 5 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertNull\(\) with int will always evaluate to false\.$#' + identifier: method.impossibleType + count: 1 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Method Tests\\Feature\\Schedule\\ScheduleEdgeCasesTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Parameter \#1 \$user of method Illuminate\\Foundation\\Testing\\TestCase\:\:actingAs\(\) expects Illuminate\\Contracts\\Auth\\Authenticatable, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Property Tests\\Feature\\Schedule\\ScheduleEdgeCasesTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Schedule/ScheduleEdgeCasesTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ScheduleUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ScheduleUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ScheduleUserDishTest.php + + - + message: '#^Parameter \#1 \$user of method Illuminate\\Foundation\\Testing\\TestCase\:\:actingAs\(\) expects Illuminate\\Contracts\\Auth\\Authenticatable, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/ScheduleUserDishTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$dish_id\.$#' + identifier: property.notFound + count: 1 + path: tests/Feature/Schedule/UpdateScheduleTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$user_dish_id\.$#' + identifier: property.notFound + count: 1 + path: tests/Feature/Schedule/UpdateScheduleTest.php + + - + message: '#^Method Tests\\Feature\\Schedule\\UpdateScheduleTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/Schedule/UpdateScheduleTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/Schedule/UpdateScheduleTest.php + + - + message: '#^Property Tests\\Feature\\Schedule\\UpdateScheduleTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/Schedule/UpdateScheduleTest.php + + - + message: '#^Called ''first'' on Laravel collection, but could have been retrieved as a query\.$#' + identifier: larastan.noUnnecessaryCollectionCall + count: 1 + path: tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php + + - + message: '#^Method Tests\\Feature\\ScheduledUserDish\\CreateScheduledUserDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php + + - + message: '#^Property Tests\\Feature\\ScheduledUserDish\\CreateScheduledUserDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php + + - + message: '#^Method Tests\\Feature\\ScheduledUserDish\\DeleteScheduledUserDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php + + - + message: '#^Property Tests\\Feature\\ScheduledUserDish\\DeleteScheduledUserDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$user\.$#' + identifier: property.notFound + count: 2 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Method Tests\\Feature\\ScheduledUserDish\\ReadScheduledUserDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Property Tests\\Feature\\ScheduledUserDish\\ReadScheduledUserDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$dish\.$#' + identifier: property.notFound + count: 2 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 3 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$user\.$#' + identifier: property.notFound + count: 4 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Method Tests\\Feature\\ScheduledUserDish\\UpdateScheduledUserDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Method Tests\\Feature\\ScheduledUserDish\\UpdateScheduledUserDishTest\:\:generateDishes\(\) return type with generic class Illuminate\\Support\\Collection does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 2 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Tests\\Feature\\ScheduledUserDish\\UpdateScheduledUserDishTest\:\:generateDishes\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Tests\\Feature\\ScheduledUserDish\\UpdateScheduledUserDishTest\:\:generateScheduledDishes\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model\|null given\.$#' + identifier: argument.type + count: 2 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Property Tests\\Feature\\ScheduledUserDish\\UpdateScheduledUserDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Unable to resolve the template type TKey in call to function collect$#' + identifier: argument.templateType + count: 1 + path: tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php + + - + message: '#^Method Tests\\Feature\\User\\CreateUserTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/CreateUserTest.php + + - + message: '#^Property Tests\\Feature\\User\\CreateUserTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/CreateUserTest.php + + - + message: '#^Method Tests\\Feature\\User\\DeleteUserTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/DeleteUserTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/DeleteUserTest.php + + - + message: '#^Property Tests\\Feature\\User\\DeleteUserTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/DeleteUserTest.php + + - + message: '#^Method Tests\\Feature\\User\\Dish\\ListUserDishesTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/Dish/ListUserDishesTest.php + + - + message: '#^Parameter \#1 \$user of method Illuminate\\Foundation\\Testing\\TestCase\:\:actingAs\(\) expects Illuminate\\Contracts\\Auth\\Authenticatable, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/Dish/ListUserDishesTest.php + + - + message: '#^Property Tests\\Feature\\User\\Dish\\ListUserDishesTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/Dish/ListUserDishesTest.php + + - + message: '#^Method Tests\\Feature\\User\\Dish\\RemoveDishesForUserTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/Dish/RemoveDishesForUserTest.php + + - + message: '#^Property Tests\\Feature\\User\\Dish\\RemoveDishesForUserTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/Dish/RemoveDishesForUserTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: tests/Feature/User/Dish/ShowUserDishTest.php + + - + message: '#^Method Tests\\Feature\\User\\Dish\\ShowUserDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/Dish/ShowUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/Dish/ShowUserDishTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/Dish/ShowUserDishTest.php + + - + message: '#^Property Tests\\Feature\\User\\Dish\\ShowUserDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/Dish/ShowUserDishTest.php + + - + message: '#^Method Tests\\Feature\\User\\Dish\\StoreRecurrenceForUserDishTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/Dish/StoreRecurrenceForUserDishTest.php + + - + message: '#^Property Tests\\Feature\\User\\Dish\\StoreRecurrenceForUserDishTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/Dish/StoreRecurrenceForUserDishTest.php + + - + message: '#^Method Tests\\Feature\\User\\ListUsersTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/ListUsersTest.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:map\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: array\{id\: int, dish\: array\{id\: int, name\: string\}, recurrences\: array\{\}\}, Closure\(App\\Models\\UserDish\)\: array\{id\: int, dish\: array\{id\: int, name\: string\}, recurrences\: array\{\}\} given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/ListUsersTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/ListUsersTest.php + + - + message: '#^Property Tests\\Feature\\User\\ListUsersTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/ListUsersTest.php + + - + message: '#^Method Tests\\Feature\\User\\ShowUserTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/ShowUserTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/ShowUserTest.php + + - + message: '#^Property Tests\\Feature\\User\\ShowUserTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/ShowUserTest.php + + - + message: '#^Method Tests\\Feature\\User\\ShowUserWithDishesTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/ShowUserWithDishesTest.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Database\\Eloquent\\Collection\<\(int\|string\),Illuminate\\Database\\Eloquent\\Model\>\:\:map\(\) expects callable\(Illuminate\\Database\\Eloquent\\Model, int\|string\)\: array\{id\: int, dish\: array\{id\: int, name\: string\}, recurrences\: array\{\}\}, Closure\(App\\Models\\UserDish\)\: array\{id\: int, dish\: array\{id\: int, name\: string\}, recurrences\: array\{\}\} given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/ShowUserWithDishesTest.php + + - + message: '#^Property Tests\\Feature\\User\\ShowUserWithDishesTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/ShowUserWithDishesTest.php + + - + message: '#^Method Tests\\Feature\\User\\UpdateUserTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Feature/User/UpdateUserTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Feature/User/UpdateUserTest.php + + - + message: '#^Property Tests\\Feature\\User\\UpdateUserTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Feature/User/UpdateUserTest.php + + - + message: '#^Method Tests\\Unit\\Actions\\EditUserActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Actions/EditUserActionTest.php + + - + message: '#^Parameter \#1 \$user of method App\\Actions\\User\\EditUserAction\:\:execute\(\) expects App\\Models\\User, Mockery\\MockInterface given\.$#' + identifier: argument.type + count: 3 + path: tests/Unit/Actions/EditUserActionTest.php + + - + message: '#^Property Tests\\Unit\\Actions\\EditUserActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 2 + path: tests/Unit/Actions/EditUserActionTest.php + + - + message: '#^Method Tests\\Unit\\Actions\\RegenerateScheduleDayActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayActionTest.php + + - + message: '#^Method Tests\\Unit\\Actions\\RegenerateScheduleDayActionTest\:\:generateDishes\(\) return type with generic class Illuminate\\Support\\Collection does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayActionTest.php + + - + message: '#^Property Tests\\Unit\\Actions\\RegenerateScheduleDayActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayActionTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 2 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertNotNull\(\) with App\\Models\\UserDish will always evaluate to true\.$#' + identifier: method.alreadyNarrowedType + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertNotNull\(\) with int will always evaluate to true\.$#' + identifier: method.alreadyNarrowedType + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Called ''first'' on Laravel collection, but could have been retrieved as a query\.$#' + identifier: larastan.noUnnecessaryCollectionCall + count: 3 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Method Tests\\Unit\\Actions\\RegenerateScheduleDayForUserActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^PHPDoc tag @var for variable \$dishes contains generic class Illuminate\\Database\\Eloquent\\Collection but does not specify its types\: TKey, TModel$#' + identifier: missingType.generics + count: 2 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Parameter \#1 \$userDish of method Database\\Factories\\ScheduledUserDishFactory\:\:userDish\(\) expects App\\Models\\UserDish, Illuminate\\Database\\Eloquent\\Model given\.$#' + identifier: argument.type + count: 2 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Property Tests\\Unit\\Actions\\RegenerateScheduleDayForUserActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php + + - + message: '#^Call to an undefined static method Illuminate\\Support\\Facades\\Log\:\:shouldHaveReceived\(\)\.$#' + identifier: staticMethod.notFound + count: 3 + path: tests/Unit/Actions/User/CreateUserActionTest.php + + - + message: '#^Property Tests\\Unit\\Actions\\User\\CreateUserActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Actions/User/CreateUserActionTest.php + + - + message: '#^Call to an undefined static method Illuminate\\Support\\Facades\\Log\:\:shouldHaveReceived\(\)\.$#' + identifier: staticMethod.notFound + count: 3 + path: tests/Unit/Actions/User/DeleteUserActionTest.php + + - + message: '#^Property Tests\\Unit\\Actions\\User\\DeleteUserActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Actions/User/DeleteUserActionTest.php + + - + message: '#^Property Tests\\Unit\\Actions\\UserActionIntegrationTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Actions/UserActionIntegrationTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Actions\\ClearScheduleForMonthActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/Actions/ClearScheduleForMonthActionTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\Actions\\ClearScheduleForMonthActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/Actions/ClearScheduleForMonthActionTest.php + + - + message: '#^Called ''count'' on Laravel collection, but could have been retrieved as a query\.$#' + identifier: larastan.noUnnecessaryCollectionCall + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Actions\\DraftScheduleForDateActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\Actions\\DraftScheduleForDateActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php + + - + message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertNotNull\(\) with App\\Models\\Planner will always evaluate to true\.$#' + identifier: method.alreadyNarrowedType + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php + + - + message: '#^Called ''count'' on Laravel collection, but could have been retrieved as a query\.$#' + identifier: larastan.noUnnecessaryCollectionCall + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Actions\\DraftScheduleForPeriodActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Actions\\DraftScheduleForPeriodActionTest\:\:generateDishes\(\) return type with generic class Illuminate\\Support\\Collection does not specify its types\: TKey, TValue$#' + identifier: missingType.generics + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\Actions\\DraftScheduleForPeriodActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Actions\\GenerateScheduleForMonthActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/Actions/GenerateScheduleForMonthActionTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\Actions\\GenerateScheduleForMonthActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/Actions/GenerateScheduleForMonthActionTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Actions\\RegenerateScheduleForDateForUsersActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\Actions\\RegenerateScheduleForDateForUsersActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$userDish\.$#' + identifier: property.notFound + count: 3 + path: tests/Unit/Schedule/ScheduleGeneratorTest.php + + - + message: '#^Called ''isNotEmpty'' on Laravel collection, but could have been retrieved as a query\.$#' + identifier: larastan.noUnnecessaryCollectionCall + count: 2 + path: tests/Unit/Schedule/ScheduleGeneratorTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\ScheduleGeneratorTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/ScheduleGeneratorTest.php + + - + message: '#^Parameter \#1 \$callback of method Illuminate\\Support\\Collection\\:\:reduce\(\) expects callable\(Illuminate\\Support\\Carbon\|null, Carbon\\Carbon, int\)\: Illuminate\\Support\\Carbon, Closure\(Illuminate\\Support\\Carbon\|null, Illuminate\\Support\\Carbon\)\: Illuminate\\Support\\Carbon given\.$#' + identifier: argument.type + count: 1 + path: tests/Unit/Schedule/ScheduleGeneratorTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\ScheduleGeneratorTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/ScheduleGeneratorTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 3 + path: tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php + + - + message: '#^Method Tests\\Unit\\Schedule\\Services\\ScheduleCalendarServiceTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php + + - + message: '#^Property Tests\\Unit\\Schedule\\Services\\ScheduleCalendarServiceTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php + + - + message: '#^Method Tests\\Unit\\ScheduleRepositoryTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/ScheduleRepositoryTest.php + + - + message: '#^Property Tests\\Unit\\ScheduleRepositoryTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/ScheduleRepositoryTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 4 + path: tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php + + - + message: '#^Method Tests\\Unit\\ScheduledUserDish\\Actions\\DeleteScheduledUserDishForDateActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php + + - + message: '#^Property Tests\\Unit\\ScheduledUserDish\\Actions\\DeleteScheduledUserDishForDateActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 3 + path: tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php + + - + message: '#^Method Tests\\Unit\\ScheduledUserDish\\Actions\\SkipScheduledUserDishForDateActionTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php + + - + message: '#^Property Tests\\Unit\\ScheduledUserDish\\Actions\\SkipScheduledUserDishForDateActionTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\DishFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 2 + path: tests/Unit/UpdateScheduledUserDishActionTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\ScheduleFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Unit/UpdateScheduledUserDishActionTest.php + + - + message: '#^Parameter \#1 \$planner of method Database\\Factories\\UserFactory\:\:planner\(\) expects App\\Models\\Planner, App\\Models\\User given\.$#' + identifier: argument.type + count: 1 + path: tests/Unit/UpdateScheduledUserDishActionTest.php + + - + message: '#^Access to an undefined property Illuminate\\Database\\Eloquent\\Model\:\:\$id\.$#' + identifier: property.notFound + count: 1 + path: tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php + + - + message: '#^Method Tests\\Unit\\UserDish\\Repositories\\UserDishRepositoryTest\:\:createPlanner\(\) should return App\\Models\\Planner but returns App\\Models\\User\.$#' + identifier: return.type + count: 1 + path: tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php + + - + message: '#^Property Tests\\Unit\\UserDish\\Repositories\\UserDishRepositoryTest\:\:\$planner \(App\\Models\\Planner\) does not accept App\\Models\\User\.$#' + identifier: assign.propertyType + count: 1 + path: tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..91375f6 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,16 @@ +includes: + - vendor/larastan/larastan/extension.neon + - vendor/phpstan/phpstan-mockery/extension.neon + - phpstan-baseline.neon + +parameters: + level: 7 + paths: + - app/ + - src/ + - tests/ + + excludePaths: + - bootstrap/*.php + - storage/* + diff --git a/phpunit.xml b/phpunit.xml index 4eee333..ac5feb4 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -23,13 +23,6 @@ app/Providers - - - - - - - @@ -40,12 +33,8 @@ - - - - - - + + diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..93061b6 --- /dev/null +++ b/pint.json @@ -0,0 +1,3 @@ +{ + "preset": "laravel" +} diff --git a/routes/api.php b/routes/api.php index 28b43b3..1ad6449 100644 --- a/routes/api.php +++ b/routes/api.php @@ -5,12 +5,12 @@ Route::group([ 'as' => 'api.', ], function () { - require __DIR__ . '/api/auth.php'; + require __DIR__.'/api/auth.php'; Route::middleware('auth:sanctum')->group(function () { - require __DIR__ . '/api/users.php'; - require __DIR__ . '/api/dishes.php'; - require __DIR__ . '/api/schedule.php'; - require __DIR__ . '/api/scheduledUserDishes.php'; + require __DIR__.'/api/users.php'; + require __DIR__.'/api/dishes.php'; + require __DIR__.'/api/schedule.php'; + require __DIR__.'/api/scheduledUserDishes.php'; }); }); diff --git a/routes/api/auth.php b/routes/api/auth.php index bd944e0..b91be18 100644 --- a/routes/api/auth.php +++ b/routes/api/auth.php @@ -18,4 +18,3 @@ ->json($request->user()) )->name('me'); }); - diff --git a/routes/web.php b/routes/web.php index c1e49da..a4031ae 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,8 +1,8 @@ route('dashboard'); diff --git a/shell.nix b/shell.nix index dfcd838..3373028 100644 --- a/shell.nix +++ b/shell.nix @@ -81,7 +81,7 @@ pkgs.mkShell { } dev-test() { - podman-compose exec -T app php -d memory_limit=512M vendor/bin/phpunit "$@" + podman-compose exec -T app env $(grep -vE '^\s*(#|$)' .env.testing) php -d memory_limit=512M vendor/bin/phpunit "$@" } dev-fix-permissions() { diff --git a/src/DishPlanner/Auth/Controllers/PlannerAuthController.php b/src/DishPlanner/Auth/Controllers/PlannerAuthController.php index db9b6d1..28ea11f 100644 --- a/src/DishPlanner/Auth/Controllers/PlannerAuthController.php +++ b/src/DishPlanner/Auth/Controllers/PlannerAuthController.php @@ -17,7 +17,7 @@ public function login(Request $request): JsonResponse 'password' => ['required'], ]); - if (!Auth::attempt($credentials)) { + if (! Auth::attempt($credentials)) { return response()->json([ 'message' => 'The provided credentials are incorrect.', ], 401); diff --git a/src/DishPlanner/Dish/Controllers/DishController.php b/src/DishPlanner/Dish/Controllers/DishController.php index 02e183c..e63457d 100644 --- a/src/DishPlanner/Dish/Controllers/DishController.php +++ b/src/DishPlanner/Dish/Controllers/DishController.php @@ -31,7 +31,7 @@ public function index(): JsonResponse public function store(StoreDishRequest $request): JsonResponse { - $dish = (new CreateDishAction())->execute($request->validated()); + $dish = (new CreateDishAction)->execute($request->validated()); return $this->success(['dish' => new DishResource($dish)]); } @@ -47,7 +47,7 @@ public function update(UpdateDishRequest $request, Dish $dish): JsonResponse { Gate::authorize('update', $dish); - $dish = (new UpdateDishAction())->execute($dish, $request->validated()); + $dish = (new UpdateDishAction)->execute($dish, $request->validated()); return $this->success(['dish' => new DishResource($dish)]); } @@ -56,14 +56,14 @@ public function destroy(Dish $dish): JsonResponse { Gate::authorize('delete', $dish); - (new DeleteDishAction())->execute($dish); + (new DeleteDishAction)->execute($dish); return $this->success(null); } public function syncUsers(SyncUsersRequest $request, Dish $dish): JsonResponse { - (new SyncUsersAction())->execute($dish, Arr::get($request->validated(), 'users', [])); + (new SyncUsersAction)->execute($dish, Arr::get($request->validated(), 'users', [])); return $this->success(['dish' => new DishResource($dish->refresh())]); } @@ -72,14 +72,14 @@ public function addUsers(AddUsersToDishRequest $request, Dish $dish): JsonRespon { Gate::authorize('update', $dish); - (new AddUsersToDishAction())->execute($dish, Arr::get($request->validated(), 'users', [])); + (new AddUsersToDishAction)->execute($dish, Arr::get($request->validated(), 'users', [])); return $this->success(['dish' => new DishResource($dish->refresh())]); } public function removeUsers(RemoveUsersFromDishRequest $request, Dish $dish): JsonResponse { - (new RemoveUsersFromDishAction())->execute($dish, Arr::get($request->validated(), 'users', [])); + (new RemoveUsersFromDishAction)->execute($dish, Arr::get($request->validated(), 'users', [])); return $this->success(['dish' => new DishResource($dish->refresh())]); } diff --git a/src/DishPlanner/Dish/Exceptions/InvalidDishException.php b/src/DishPlanner/Dish/Exceptions/InvalidDishException.php index 3ab82b6..805f684 100644 --- a/src/DishPlanner/Dish/Exceptions/InvalidDishException.php +++ b/src/DishPlanner/Dish/Exceptions/InvalidDishException.php @@ -7,5 +7,6 @@ class InvalidDishException extends CustomException { protected $message = 'INVALID_DISH'; + protected $code = 422; } diff --git a/src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php b/src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php index 1375ad5..77ea2ff 100644 --- a/src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php +++ b/src/DishPlanner/Schedule/Actions/DraftScheduleForDateAction.php @@ -11,7 +11,7 @@ class DraftScheduleForDateAction public function execute(Schedule $schedule): Schedule { User::all() - ->reject(fn($user) => $schedule + ->reject(fn ($user) => $schedule ->scheduledUserDishes ->map(fn (ScheduledUserDish $scheduledUserDish) => $scheduledUserDish->userDish?->user) ->filter() diff --git a/src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php b/src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php index 1f5937d..05e1c09 100644 --- a/src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php +++ b/src/DishPlanner/Schedule/Actions/GenerateScheduleForMonthAction.php @@ -7,7 +7,6 @@ use App\Models\ScheduledUserDish; use App\Models\User; use Carbon\Carbon; -use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; class GenerateScheduleForMonthAction @@ -84,7 +83,7 @@ private function generateSchedulesForPeriod( ); foreach ($userIds as $userId) { - if (!isset($userDishesMap[$userId]) || $userDishesMap[$userId]->isEmpty()) { + if (! isset($userDishesMap[$userId]) || $userDishesMap[$userId]->isEmpty()) { continue; } diff --git a/src/DishPlanner/Schedule/Actions/RegenerateScheduleDayForUserAction.php b/src/DishPlanner/Schedule/Actions/RegenerateScheduleDayForUserAction.php index a27de32..c952cd9 100644 --- a/src/DishPlanner/Schedule/Actions/RegenerateScheduleDayForUserAction.php +++ b/src/DishPlanner/Schedule/Actions/RegenerateScheduleDayForUserAction.php @@ -29,7 +29,7 @@ public function execute(Planner $planner, Schedule $schedule, User $user, bool $ ); } - if (!$overwrite && $scheduledUserDish->userDish) { + if (! $overwrite && $scheduledUserDish->userDish) { return $scheduledUserDish; } diff --git a/src/DishPlanner/Schedule/Controllers/ScheduleController.php b/src/DishPlanner/Schedule/Controllers/ScheduleController.php index 5dd9f6c..4adcaef 100644 --- a/src/DishPlanner/Schedule/Controllers/ScheduleController.php +++ b/src/DishPlanner/Schedule/Controllers/ScheduleController.php @@ -5,8 +5,6 @@ use App\Http\Controllers\Api\ApiController; use App\Models\Planner; use App\Models\Schedule; -use Carbon\CarbonPeriod; -use DishPlanner\Schedule\Actions\DraftScheduleForPeriodAction; use DishPlanner\Schedule\Actions\GenerateScheduleForPeriodAction; use DishPlanner\Schedule\Actions\UpdateScheduleAction; use DishPlanner\Schedule\Repositories\ScheduleRepository; @@ -83,7 +81,7 @@ public function generate(GenerateScheduleRequest $request): JsonResponse /** @var Planner $planner */ $planner = auth()->user(); - (new GenerateScheduleForPeriodAction())->execute($planner, $request->get('overwrite', false)); + (new GenerateScheduleForPeriodAction)->execute($planner, $request->get('overwrite', false)); return $this->success(null); } diff --git a/src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php b/src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php index f94082a..606c8dc 100644 --- a/src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php +++ b/src/DishPlanner/Schedule/Controllers/ScheduleUserDishController.php @@ -37,7 +37,7 @@ public function __invoke(ScheduleUserDishRequest $request, Carbon $date): JsonRe ->first(); if (! $scheduledUserDish) { - $scheduledUserDish = new ScheduledUserDish(); + $scheduledUserDish = new ScheduledUserDish; } abort_if( diff --git a/src/DishPlanner/Schedule/Requests/ScheduleUserDishRequest.php b/src/DishPlanner/Schedule/Requests/ScheduleUserDishRequest.php index 94f845a..040d2c7 100644 --- a/src/DishPlanner/Schedule/Requests/ScheduleUserDishRequest.php +++ b/src/DishPlanner/Schedule/Requests/ScheduleUserDishRequest.php @@ -12,7 +12,7 @@ public function rules(): array 'user_dish_id' => [ 'required_without:skipped', 'exists:user_dishes,id', - 'nullable' + 'nullable', ], 'user_id' => ['required', 'exists:users,id'], 'skipped' => ['required_if:user_dish_id,null', 'boolean'], diff --git a/src/DishPlanner/Schedule/Requests/UpdateScheduleRequest.php b/src/DishPlanner/Schedule/Requests/UpdateScheduleRequest.php index 895515e..2a57c98 100755 --- a/src/DishPlanner/Schedule/Requests/UpdateScheduleRequest.php +++ b/src/DishPlanner/Schedule/Requests/UpdateScheduleRequest.php @@ -5,7 +5,7 @@ use Illuminate\Foundation\Http\FormRequest; /** - * @property boolean $is_skipped + * @property bool $is_skipped */ class UpdateScheduleRequest extends FormRequest { diff --git a/src/DishPlanner/Schedule/Services/ScheduleCalendarService.php b/src/DishPlanner/Schedule/Services/ScheduleCalendarService.php index 8b64d3d..ca967e2 100644 --- a/src/DishPlanner/Schedule/Services/ScheduleCalendarService.php +++ b/src/DishPlanner/Schedule/Services/ScheduleCalendarService.php @@ -43,7 +43,7 @@ private function buildCalendarDays(int $year, int $month, int $daysInMonth, Coll 'date' => $date, 'isToday' => $date->isToday(), 'scheduledDishes' => $scheduledDishes, - 'isEmpty' => $scheduledDishes->isEmpty() + 'isEmpty' => $scheduledDishes->isEmpty(), ]; } else { $calendarDays[] = [ @@ -51,7 +51,7 @@ private function buildCalendarDays(int $year, int $month, int $daysInMonth, Coll 'date' => null, 'isToday' => false, 'scheduledDishes' => collect(), - 'isEmpty' => true + 'isEmpty' => true, ]; } } diff --git a/src/DishPlanner/Schedule/Services/ScheduleGenerator.php b/src/DishPlanner/Schedule/Services/ScheduleGenerator.php index 5e86f48..e9beed0 100644 --- a/src/DishPlanner/Schedule/Services/ScheduleGenerator.php +++ b/src/DishPlanner/Schedule/Services/ScheduleGenerator.php @@ -31,7 +31,7 @@ public function generate(Planner $planner): void $users->each(function (User $user) use ($date, $planner, $scheduleRepository, $userDishRepository) { $schedule = $scheduleRepository->findOrCreate($planner, $date); - (new CreateScheduledUserDishAction())->execute( + (new CreateScheduledUserDishAction)->execute( planner: $planner, schedule: $schedule, userDish: $userDishRepository->getRandomForDate($user, $date) diff --git a/src/DishPlanner/ScheduledUserDish/Actions/CreateScheduledUserDishAction.php b/src/DishPlanner/ScheduledUserDish/Actions/CreateScheduledUserDishAction.php index 9ab9994..dc79086 100644 --- a/src/DishPlanner/ScheduledUserDish/Actions/CreateScheduledUserDishAction.php +++ b/src/DishPlanner/ScheduledUserDish/Actions/CreateScheduledUserDishAction.php @@ -16,7 +16,7 @@ class CreateScheduledUserDishAction public function execute(Planner $planner, Schedule $schedule, UserDish $userDish): ScheduledUserDish { if ($userDish->dish->planner_id !== $planner->id || $userDish->user->planner_id !== $planner->id) { - throw new InvalidPlannerException(); + throw new InvalidPlannerException; } return ScheduledUserDish::create([ diff --git a/src/DishPlanner/ScheduledUserDish/Controllers/ScheduledUserDishController.php b/src/DishPlanner/ScheduledUserDish/Controllers/ScheduledUserDishController.php index db4b912..017f550 100644 --- a/src/DishPlanner/ScheduledUserDish/Controllers/ScheduledUserDishController.php +++ b/src/DishPlanner/ScheduledUserDish/Controllers/ScheduledUserDishController.php @@ -36,7 +36,7 @@ public function create(CreateScheduleRequest $request): JsonResponse $schedule = resolve(ScheduleRepository::class)->findOrCreate($planner, $date); try { - $scheduledUserDish = (new CreateScheduledUserDishAction())->execute( + $scheduledUserDish = (new CreateScheduledUserDishAction)->execute( planner: $planner, schedule: $schedule, userDish: $userDish, @@ -46,7 +46,7 @@ public function create(CreateScheduleRequest $request): JsonResponse } return $this->success([ - 'scheduled_user_dish' => new ScheduledUserDishResource($scheduledUserDish) + 'scheduled_user_dish' => new ScheduledUserDishResource($scheduledUserDish), ]); } @@ -63,7 +63,7 @@ public function update(UpdateScheduledUserDishRequest $request, ScheduledUserDis { Gate::authorize('update', $scheduledUserDish); - (new UpdateScheduledUserDishAction())->execute( + (new UpdateScheduledUserDishAction)->execute( scheduledUserDish: $scheduledUserDish, userDish: UserDish::find($request->user_dish_id), isSkipped: $request->is_skipped ?? null, @@ -78,7 +78,7 @@ public function delete(ScheduledUserDish $scheduledUserDish): JsonResponse { Gate::authorize('delete', $scheduledUserDish); - (new DeleteScheduledUserDishAction())->execute($scheduledUserDish); + (new DeleteScheduledUserDishAction)->execute($scheduledUserDish); return $this->success(null); } diff --git a/src/DishPlanner/ScheduledUserDish/Policies/ScheduledUserDishPolicy.php b/src/DishPlanner/ScheduledUserDish/Policies/ScheduledUserDishPolicy.php index dafe218..ce2c735 100644 --- a/src/DishPlanner/ScheduledUserDish/Policies/ScheduledUserDishPolicy.php +++ b/src/DishPlanner/ScheduledUserDish/Policies/ScheduledUserDishPolicy.php @@ -4,7 +4,6 @@ use App\Models\Planner; use App\Models\ScheduledUserDish; -use DishPlanner\UserDish\Policies\UserDishPolicy; use Illuminate\Support\Facades\Gate; class ScheduledUserDishPolicy diff --git a/src/DishPlanner/User/Actions/DeleteUserAction.php b/src/DishPlanner/User/Actions/DeleteUserAction.php index a18a120..1d8740b 100644 --- a/src/DishPlanner/User/Actions/DeleteUserAction.php +++ b/src/DishPlanner/User/Actions/DeleteUserAction.php @@ -2,7 +2,6 @@ namespace DishPlanner\User\Actions; -use App\Models\Planner; use App\Models\User; class DeleteUserAction diff --git a/src/DishPlanner/User/Actions/UpdateUserAction.php b/src/DishPlanner/User/Actions/UpdateUserAction.php index c59c77c..a0b3924 100644 --- a/src/DishPlanner/User/Actions/UpdateUserAction.php +++ b/src/DishPlanner/User/Actions/UpdateUserAction.php @@ -2,7 +2,6 @@ namespace DishPlanner\User\Actions; -use App\Models\Planner; use App\Models\User; class UpdateUserAction diff --git a/src/DishPlanner/User/Controllers/UserController.php b/src/DishPlanner/User/Controllers/UserController.php index 9890708..df0a776 100644 --- a/src/DishPlanner/User/Controllers/UserController.php +++ b/src/DishPlanner/User/Controllers/UserController.php @@ -33,7 +33,7 @@ public function create(CreateUserRequest $request): JsonResponse $requestData = $request->validated(); - $user = (new CreateUserAction()) + $user = (new CreateUserAction) ->execute($planner, Arr::get($requestData, 'name')); return $this->success(['user' => new UserResource($user)]); @@ -43,7 +43,7 @@ public function update(UpdateUserRequest $request, User $user): JsonResponse { Gate::authorize('update', $user); - $user = (new UpdateUserAction()) + $user = (new UpdateUserAction) ->execute($user, Arr::get($request->validated(), 'name')); return $this->success(['user' => new UserResource($user)]); @@ -53,7 +53,7 @@ public function delete(User $user): JsonResponse { Gate::authorize('delete', $user); - (new DeleteUserAction())->execute($user); + (new DeleteUserAction)->execute($user); return $this->success(null, 201); } diff --git a/src/DishPlanner/UserDish/Actions/CreateFixedRecurrenceAction.php b/src/DishPlanner/UserDish/Actions/CreateFixedRecurrenceAction.php index 709e4df..3d149c2 100644 --- a/src/DishPlanner/UserDish/Actions/CreateFixedRecurrenceAction.php +++ b/src/DishPlanner/UserDish/Actions/CreateFixedRecurrenceAction.php @@ -17,8 +17,8 @@ class CreateFixedRecurrenceAction */ public function execute(UserDish $userDish, string $recurrenceType, int $value): void { - if (!in_array($recurrenceType, self::FIXED_RECURRENCES)) { - throw new InvalidRecurrenceTypeException(); + if (! in_array($recurrenceType, self::FIXED_RECURRENCES)) { + throw new InvalidRecurrenceTypeException; } $recurrence = $recurrenceType::create([ diff --git a/src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php b/src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php index 18e0f19..e6d7df2 100644 --- a/src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php +++ b/src/DishPlanner/UserDish/Actions/CreateMinimumRecurrenceAction.php @@ -15,7 +15,7 @@ class CreateMinimumRecurrenceAction public function execute(UserDish $userDish, string $recurrenceType, int $recurrenceValue): void { if ($recurrenceType !== MinimumRecurrence::class) { - throw new InvalidRecurrenceTypeException(); + throw new InvalidRecurrenceTypeException; } $existingRecurrenceForDay = $userDish diff --git a/src/DishPlanner/UserDish/Actions/CreateUserDishAction.php b/src/DishPlanner/UserDish/Actions/CreateUserDishAction.php index a21f2a6..1ead2e1 100644 --- a/src/DishPlanner/UserDish/Actions/CreateUserDishAction.php +++ b/src/DishPlanner/UserDish/Actions/CreateUserDishAction.php @@ -40,11 +40,11 @@ private function addRecurrences(UserDish $userDish, array $data): void } if ($recurrenceType === WeeklyRecurrence::class) { - (new CreateFixedRecurrenceAction())->execute($userDish, $recurrenceType, $recurrenceValue); + (new CreateFixedRecurrenceAction)->execute($userDish, $recurrenceType, $recurrenceValue); } elseif ($recurrenceType === MinimumRecurrence::class) { - (new CreateMinimumRecurrenceAction())->execute($userDish, $recurrenceType, $recurrenceValue); + (new CreateMinimumRecurrenceAction)->execute($userDish, $recurrenceType, $recurrenceValue); } else { - throw new InvalidRecurrenceTypeException(); + throw new InvalidRecurrenceTypeException; } } } diff --git a/src/DishPlanner/UserDish/Actions/DeleteFixedRecurrenceAction.php b/src/DishPlanner/UserDish/Actions/DeleteFixedRecurrenceAction.php index a9d7701..063a2c6 100644 --- a/src/DishPlanner/UserDish/Actions/DeleteFixedRecurrenceAction.php +++ b/src/DishPlanner/UserDish/Actions/DeleteFixedRecurrenceAction.php @@ -14,7 +14,7 @@ class DeleteFixedRecurrenceAction public function execute(RecurrenceInterface $recurrence): void { if (! $recurrence instanceof WeeklyRecurrence) { - throw new InvalidRecurrenceTypeException(); + throw new InvalidRecurrenceTypeException; } $recurrence->delete(); diff --git a/src/DishPlanner/UserDish/Actions/DeleteMinimumRecurrenceAction.php b/src/DishPlanner/UserDish/Actions/DeleteMinimumRecurrenceAction.php index cfc8044..12d89c6 100644 --- a/src/DishPlanner/UserDish/Actions/DeleteMinimumRecurrenceAction.php +++ b/src/DishPlanner/UserDish/Actions/DeleteMinimumRecurrenceAction.php @@ -15,7 +15,7 @@ class DeleteMinimumRecurrenceAction public function execute(RecurrenceInterface $recurrence): void { if (! $recurrence instanceof MinimumRecurrence) { - throw new InvalidRecurrenceTypeException(); + throw new InvalidRecurrenceTypeException; } UserDishRecurrence::query() diff --git a/src/DishPlanner/UserDish/Actions/SyncRecurrencesForUserDishAction.php b/src/DishPlanner/UserDish/Actions/SyncRecurrencesForUserDishAction.php index 2099712..dde4e41 100644 --- a/src/DishPlanner/UserDish/Actions/SyncRecurrencesForUserDishAction.php +++ b/src/DishPlanner/UserDish/Actions/SyncRecurrencesForUserDishAction.php @@ -32,9 +32,9 @@ public function execute(UserDish $userDish, Collection $recurrences): UserDish } match ($recurrenceType) { - WeeklyRecurrence::class => (new CreateFixedRecurrenceAction())->execute($userDish, $recurrenceType, $recurrenceValue), - MinimumRecurrence::class => (new CreateMinimumRecurrenceAction())->execute($userDish, $recurrenceType, $recurrenceValue), - default => throw new InvalidRecurrenceTypeException(), + WeeklyRecurrence::class => (new CreateFixedRecurrenceAction)->execute($userDish, $recurrenceType, $recurrenceValue), + MinimumRecurrence::class => (new CreateMinimumRecurrenceAction)->execute($userDish, $recurrenceType, $recurrenceValue), + default => throw new InvalidRecurrenceTypeException, }; }); diff --git a/src/DishPlanner/UserDish/Actions/UpdateFixedRecurrenceAction.php b/src/DishPlanner/UserDish/Actions/UpdateFixedRecurrenceAction.php index bd4d43b..b4bca06 100644 --- a/src/DishPlanner/UserDish/Actions/UpdateFixedRecurrenceAction.php +++ b/src/DishPlanner/UserDish/Actions/UpdateFixedRecurrenceAction.php @@ -15,7 +15,7 @@ class UpdateFixedRecurrenceAction public function execute(RecurrenceInterface $recurrence, array $data): RecurrenceInterface { if (! $recurrence instanceof WeeklyRecurrence) { - throw new InvalidRecurrenceTypeException(); + throw new InvalidRecurrenceTypeException; } $weekday = Arr::get($data, 'recurrence_data.weekday'); diff --git a/src/DishPlanner/UserDish/Actions/UpdateMinimumRecurrenceAction.php b/src/DishPlanner/UserDish/Actions/UpdateMinimumRecurrenceAction.php index 0142dad..99f8515 100644 --- a/src/DishPlanner/UserDish/Actions/UpdateMinimumRecurrenceAction.php +++ b/src/DishPlanner/UserDish/Actions/UpdateMinimumRecurrenceAction.php @@ -15,7 +15,7 @@ class UpdateMinimumRecurrenceAction public function execute(RecurrenceInterface $recurrence, array $data): RecurrenceInterface { if (! $recurrence instanceof MinimumRecurrence) { - throw new InvalidRecurrenceTypeException(); + throw new InvalidRecurrenceTypeException; } $days = Arr::get($data, 'recurrence_data.days'); diff --git a/src/DishPlanner/UserDish/Controllers/ListUserDishesController.php b/src/DishPlanner/UserDish/Controllers/ListUserDishesController.php index c515152..343fa6f 100644 --- a/src/DishPlanner/UserDish/Controllers/ListUserDishesController.php +++ b/src/DishPlanner/UserDish/Controllers/ListUserDishesController.php @@ -20,7 +20,7 @@ public function __invoke(Request $request) $userDishes = $userDishRepository->getAllForPlanner($planner); return $this->success([ - 'user_dishes' => UserDishResource::collection($userDishes)->collection->toArray() + 'user_dishes' => UserDishResource::collection($userDishes)->collection->toArray(), ]); } } diff --git a/src/DishPlanner/UserDish/Controllers/UserDishController.php b/src/DishPlanner/UserDish/Controllers/UserDishController.php index 23eea18..63b79dd 100644 --- a/src/DishPlanner/UserDish/Controllers/UserDishController.php +++ b/src/DishPlanner/UserDish/Controllers/UserDishController.php @@ -48,7 +48,7 @@ public function show(User $user, Dish $dish): JsonResponse */ public function store(CreateUserDishRequest $request, User $user, Dish $dish): JsonResponse { - $userDish = (new CreateUserDishAction())->execute($dish, $user, $request->validated()); + $userDish = (new CreateUserDishAction)->execute($dish, $user, $request->validated()); return $this->success([ 'user_dish' => new UserDishResource($userDish), @@ -57,7 +57,7 @@ public function store(CreateUserDishRequest $request, User $user, Dish $dish): J public function destroy(User $user, Dish $dish): JsonResponse { - (new DeleteUserDishAction())->execute($user, $dish); + (new DeleteUserDishAction)->execute($user, $dish); return $this->success(null); } diff --git a/src/DishPlanner/UserDish/Controllers/UserDishRecurrenceController.php b/src/DishPlanner/UserDish/Controllers/UserDishRecurrenceController.php index 425fba1..2398918 100644 --- a/src/DishPlanner/UserDish/Controllers/UserDishRecurrenceController.php +++ b/src/DishPlanner/UserDish/Controllers/UserDishRecurrenceController.php @@ -35,7 +35,7 @@ public function store(StoreUserDishRecurrenceRequest $request, User $user, Dish $recurrences = collect($request->validated()); - (new SyncRecurrencesForUserDishAction())->execute($userDish, $recurrences); + (new SyncRecurrencesForUserDishAction)->execute($userDish, $recurrences); return $this->success([ 'user_dish' => new UserDishResource($userDish->refresh()), @@ -51,9 +51,9 @@ public function update(UpdateUserDishFixedRecurrenceRequest $request, UserDish $ $recurrence = $recurrenceClass::findOrFail($recurrenceId); if ($recurrence instanceof WeeklyRecurrence) { - (new UpdateFixedRecurrenceAction())->execute($recurrence, $request->validated()); + (new UpdateFixedRecurrenceAction)->execute($recurrence, $request->validated()); } elseif ($recurrenceClass === MinimumRecurrence::class) { - (new UpdateMinimumRecurrenceAction())->execute($recurrence, $request->validated()); + (new UpdateMinimumRecurrenceAction)->execute($recurrence, $request->validated()); } else { return $this->error('invalid recurrence type'); } @@ -72,9 +72,9 @@ public function destroy(UserDish $userDish, string $recurrenceType, int $recurre $recurrence = $recurrenceClass::findOrFail($recurrenceId); if ($recurrence instanceof WeeklyRecurrence) { - (new DeleteFixedRecurrenceAction())->execute($recurrence); + (new DeleteFixedRecurrenceAction)->execute($recurrence); } elseif ($recurrenceClass === MinimumRecurrence::class) { - (new DeleteMinimumRecurrenceAction())->execute($recurrence); + (new DeleteMinimumRecurrenceAction)->execute($recurrence); } else { return $this->error('invalid recurrence type'); } diff --git a/src/DishPlanner/UserDish/Interfaces/FixedRecurrenceInterface.php b/src/DishPlanner/UserDish/Interfaces/FixedRecurrenceInterface.php index c8dd5dd..47c71b8 100644 --- a/src/DishPlanner/UserDish/Interfaces/FixedRecurrenceInterface.php +++ b/src/DishPlanner/UserDish/Interfaces/FixedRecurrenceInterface.php @@ -2,5 +2,4 @@ namespace DishPlanner\UserDish\Interfaces; -interface FixedRecurrenceInterface -{} +interface FixedRecurrenceInterface {} diff --git a/src/DishPlanner/UserDish/Interfaces/RecurrenceInterface.php b/src/DishPlanner/UserDish/Interfaces/RecurrenceInterface.php index 1776126..6c8ad9a 100644 --- a/src/DishPlanner/UserDish/Interfaces/RecurrenceInterface.php +++ b/src/DishPlanner/UserDish/Interfaces/RecurrenceInterface.php @@ -2,5 +2,4 @@ namespace DishPlanner\UserDish\Interfaces; -interface RecurrenceInterface -{} +interface RecurrenceInterface {} diff --git a/src/DishPlanner/UserDish/Repositories/UserDishRepository.php b/src/DishPlanner/UserDish/Repositories/UserDishRepository.php index 789c335..fb6badf 100644 --- a/src/DishPlanner/UserDish/Repositories/UserDishRepository.php +++ b/src/DishPlanner/UserDish/Repositories/UserDishRepository.php @@ -12,7 +12,6 @@ use App\Models\WeeklyRecurrence; use Carbon\Carbon; use Carbon\CarbonPeriod; -use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Collection as SupportCollection; @@ -70,7 +69,7 @@ public function findInterferingUserDishes(User $user, Carbon $date): Collection ->get() ->flatMap(fn (Schedule $schedule) => $schedule->scheduledUserDishes) ->filter(fn (ScheduledUserDish $scheduledUserDish) => $scheduledUserDish->userDish->user_id === $user->id) - ->filter(fn(ScheduledUserDish $scheduledUserDish) => $scheduledUserDish->userDish->recurrences->contains('recurrence_type', MinimumRecurrence::class)) + ->filter(fn (ScheduledUserDish $scheduledUserDish) => $scheduledUserDish->userDish->recurrences->contains('recurrence_type', MinimumRecurrence::class)) ->filter(function (ScheduledUserDish $scheduledUserDish) use ($date) { $minimum = $scheduledUserDish->userDish ->recurrences diff --git a/src/DishPlanner/UserDish/Requests/StoreUserDishRecurrenceRequest.php b/src/DishPlanner/UserDish/Requests/StoreUserDishRecurrenceRequest.php index 2c50204..e1190eb 100644 --- a/src/DishPlanner/UserDish/Requests/StoreUserDishRecurrenceRequest.php +++ b/src/DishPlanner/UserDish/Requests/StoreUserDishRecurrenceRequest.php @@ -19,7 +19,7 @@ public function rules(): array MinimumRecurrence::class, WeeklyRecurrence::class, ]), - 'required_with:*.recurrence_value' + 'required_with:*.recurrence_value', ], '*.value' => ['sometimes', 'integer', 'required_with:*.recurrence_type'], ]; diff --git a/src/DishPlanner/UserDish/Requests/UpdateUserDishFixedRecurrenceRequest.php b/src/DishPlanner/UserDish/Requests/UpdateUserDishFixedRecurrenceRequest.php index 49b23f9..a9f81ed 100644 --- a/src/DishPlanner/UserDish/Requests/UpdateUserDishFixedRecurrenceRequest.php +++ b/src/DishPlanner/UserDish/Requests/UpdateUserDishFixedRecurrenceRequest.php @@ -14,14 +14,14 @@ public function rules(): array 'recurrence_type' => [ 'required', 'string', - 'in:' . implode(',', [ + 'in:'.implode(',', [ MinimumRecurrence::class, WeeklyRecurrence::class, ]), ], 'recurrence_data' => 'required|array', - 'recurrence_data.days' => 'required_if:recurrence_type,' . MinimumRecurrence::class . '|integer|min:1', - 'recurrence_data.weekday' => 'required_if:recurrence_type,' . WeeklyRecurrence::class . '|integer|between:0,6', + 'recurrence_data.days' => 'required_if:recurrence_type,'.MinimumRecurrence::class.'|integer|min:1', + 'recurrence_data.weekday' => 'required_if:recurrence_type,'.WeeklyRecurrence::class.'|integer|between:0,6', ]; } diff --git a/tests/Browser/Auth/LoginTest.php b/tests/Browser/Auth/LoginTest.php index 8eaa75b..fa56d89 100644 --- a/tests/Browser/Auth/LoginTest.php +++ b/tests/Browser/Auth/LoginTest.php @@ -2,15 +2,17 @@ namespace Tests\Browser\Auth; -use Laravel\Dusk\Browser; -use Tests\DuskTestCase; use App\Models\Planner; use Illuminate\Support\Facades\Hash; +use Laravel\Dusk\Browser; +use Tests\DuskTestCase; class LoginTest extends DuskTestCase { protected static $testPlanner = null; + protected static $testEmail = null; + protected static $testPassword = 'password'; protected function ensureTestPlannerExists(): void @@ -26,49 +28,49 @@ protected function ensureTestPlannerExists(): void } } - public function testSuccessfulLogin(): void + public function test_successful_login(): void { $this->ensureTestPlannerExists(); $this->browse(function (Browser $browser) { $browser->driver->manage()->deleteAllCookies(); $browser->visit('http://dishplanner_app:8000/login') - ->waitFor('input[id="email"]', self::TIMEOUT_SHORT) - ->clear('input[id="email"]') - ->type('input[id="email"]', self::$testEmail) - ->clear('input[id="password"]') - ->type('input[id="password"]', self::$testPassword) - ->press('Login') - ->waitForLocation('/dashboard', self::TIMEOUT_MEDIUM) - ->assertPathIs('/dashboard'); + ->waitFor('input[id="email"]', self::TIMEOUT_SHORT) + ->clear('input[id="email"]') + ->type('input[id="email"]', self::$testEmail) + ->clear('input[id="password"]') + ->type('input[id="password"]', self::$testPassword) + ->press('Login') + ->waitForLocation('/dashboard', self::TIMEOUT_MEDIUM) + ->assertPathIs('/dashboard'); }); } - public function testLoginWithWrongCredentials(): void + public function test_login_with_wrong_credentials(): void { $this->ensureTestPlannerExists(); $this->browse(function (Browser $browser) { $browser->driver->manage()->deleteAllCookies(); $browser->visit('http://dishplanner_app:8000/login') - ->waitFor('input[id="email"]', self::TIMEOUT_SHORT) - ->clear('input[id="email"]') - ->type('input[id="email"]', self::$testEmail) - ->clear('input[id="password"]') - ->type('input[id="password"]', 'wrongpassword') - ->press('Login') - ->pause(self::PAUSE_MEDIUM) - ->assertPathIs('/login') - ->assertSee('These credentials do not match our records'); + ->waitFor('input[id="email"]', self::TIMEOUT_SHORT) + ->clear('input[id="email"]') + ->type('input[id="email"]', self::$testEmail) + ->clear('input[id="password"]') + ->type('input[id="password"]', 'wrongpassword') + ->press('Login') + ->pause(self::PAUSE_MEDIUM) + ->assertPathIs('/login') + ->assertSee('These credentials do not match our records'); }); } - public function testLoginFormRequiredFields(): void + public function test_login_form_required_fields(): void { $this->browse(function (Browser $browser) { $browser->driver->manage()->deleteAllCookies(); $browser->visit('http://dishplanner_app:8000/login') - ->waitFor('input[id="email"]', self::TIMEOUT_SHORT); + ->waitFor('input[id="email"]', self::TIMEOUT_SHORT); // Check that both fields have the required attribute $browser->assertAttribute('input[id="email"]', 'required', 'true'); @@ -82,8 +84,8 @@ public function testLoginFormRequiredFields(): void // Test that we stay on login page if we try to submit with empty fields $browser->press('Login') - ->pause(self::PAUSE_SHORT) - ->assertPathIs('/login'); + ->pause(self::PAUSE_SHORT) + ->assertPathIs('/login'); }); } } diff --git a/tests/Browser/Components/DishModal.php b/tests/Browser/Components/DishModal.php index 7baff18..1a31400 100644 --- a/tests/Browser/Components/DishModal.php +++ b/tests/Browser/Components/DishModal.php @@ -29,7 +29,7 @@ public function selector(): string public function assert(Browser $browser): void { $browser->assertVisible($this->selector()); - + if ($this->mode === 'create') { $browser->assertSee('Add New Dish'); } else { @@ -60,12 +60,12 @@ public function elements(): array public function fillForm(Browser $browser, string $name, ?string $description = null): void { $browser->waitFor('@name-input') - ->clear('@name-input') - ->type('@name-input', $name); - + ->clear('@name-input') + ->type('@name-input', $name); + if ($description !== null && $browser->element('@description-input')) { $browser->clear('@description-input') - ->type('@description-input', $description); + ->type('@description-input', $description); } } @@ -102,4 +102,4 @@ public function assertValidationError(Browser $browser, string $message = 'requi { $browser->assertSee($message); } -} \ No newline at end of file +} diff --git a/tests/Browser/Components/LoginForm.php b/tests/Browser/Components/LoginForm.php index f526ff3..2b817ee 100644 --- a/tests/Browser/Components/LoginForm.php +++ b/tests/Browser/Components/LoginForm.php @@ -21,9 +21,9 @@ public function selector(): string public function assert(Browser $browser): void { $browser->assertVisible($this->selector()) - ->assertVisible('@email') - ->assertVisible('@password') - ->assertVisible('@submit'); + ->assertVisible('@email') + ->assertVisible('@password') + ->assertVisible('@submit'); } /** @@ -48,7 +48,7 @@ public function elements(): array public function fillForm(Browser $browser, string $email, string $password): void { $browser->type('@email', $email) - ->type('@password', $password); + ->type('@password', $password); } /** @@ -74,9 +74,9 @@ public function loginWith(Browser $browser, string $email, string $password): vo public function assertFieldsRequired(Browser $browser): void { $browser->assertAttribute('@email', 'required', 'true') - ->assertAttribute('@password', 'required', 'true') - ->assertAttribute('@email', 'type', 'email') - ->assertAttribute('@password', 'type', 'password'); + ->assertAttribute('@password', 'required', 'true') + ->assertAttribute('@email', 'type', 'email') + ->assertAttribute('@password', 'type', 'password'); } /** @@ -86,4 +86,4 @@ public function assertHasErrors(Browser $browser): void { $browser->assertPresent('@error'); } -} \ No newline at end of file +} diff --git a/tests/Browser/Dishes/CreateDishFormValidationTest.php b/tests/Browser/Dishes/CreateDishFormValidationTest.php index a59c89c..318becf 100644 --- a/tests/Browser/Dishes/CreateDishFormValidationTest.php +++ b/tests/Browser/Dishes/CreateDishFormValidationTest.php @@ -3,18 +3,19 @@ namespace Tests\Browser\Dishes; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\Pages\DishesPage; use Tests\Browser\Components\DishModal; use Tests\Browser\LoginHelpers; +use Tests\Browser\Pages\DishesPage; +use Tests\DuskTestCase; class CreateDishFormValidationTest extends DuskTestCase { use LoginHelpers; - + protected static $createDishFormValidationTestPlanner = null; + protected static $createDishFormValidationTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -22,7 +23,7 @@ protected function setUp(): void self::$testPlanner = self::$createDishFormValidationTestPlanner; self::$testEmail = self::$createDishFormValidationTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -31,19 +32,19 @@ protected function tearDown(): void parent::tearDown(); } - public function testCreateDishFormValidation(): void + public function test_create_dish_form_validation(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser); - + $browser->on(new DishesPage) - ->openCreateModal() - ->within(new DishModal('create'), function ($browser) { - $browser->fillForm('', null) - ->submit() - ->pause(2000) - ->assertValidationError('required'); - }); + ->openCreateModal() + ->within(new DishModal('create'), function ($browser) { + $browser->fillForm('', null) + ->submit() + ->pause(2000) + ->assertValidationError('required'); + }); }); } -} \ No newline at end of file +} diff --git a/tests/Browser/Dishes/CreateDishSuccessTest.php b/tests/Browser/Dishes/CreateDishSuccessTest.php index 822dc77..aad8c7c 100644 --- a/tests/Browser/Dishes/CreateDishSuccessTest.php +++ b/tests/Browser/Dishes/CreateDishSuccessTest.php @@ -3,18 +3,19 @@ namespace Tests\Browser\Dishes; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\Pages\DishesPage; use Tests\Browser\Components\DishModal; use Tests\Browser\LoginHelpers; +use Tests\Browser\Pages\DishesPage; +use Tests\DuskTestCase; class CreateDishSuccessTest extends DuskTestCase { use LoginHelpers; - + protected static $createDishSuccessTestPlanner = null; + protected static $createDishSuccessTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -22,7 +23,7 @@ protected function setUp(): void self::$testPlanner = self::$createDishSuccessTestPlanner; self::$testEmail = self::$createDishSuccessTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -31,22 +32,22 @@ protected function tearDown(): void parent::tearDown(); } - public function testCanCreateDishSuccessfully(): void + public function test_can_create_dish_successfully(): void { $this->browse(function (Browser $browser) { - $dishName = 'Test Dish ' . uniqid(); - + $dishName = 'Test Dish '.uniqid(); + $this->loginAndGoToDishes($browser); - + $browser->on(new DishesPage) - ->openCreateModal() - ->within(new DishModal('create'), function ($browser) use ($dishName) { - $browser->fillForm($dishName) - ->submit(); - }) - ->pause(3000) - ->assertDishVisible($dishName) - ->assertSee('Dish created successfully'); + ->openCreateModal() + ->within(new DishModal('create'), function ($browser) use ($dishName) { + $browser->fillForm($dishName) + ->submit(); + }) + ->pause(3000) + ->assertDishVisible($dishName) + ->assertSee('Dish created successfully'); }); } -} \ No newline at end of file +} diff --git a/tests/Browser/Dishes/CreateDishTest.php b/tests/Browser/Dishes/CreateDishTest.php index 9a333e1..c20a99c 100644 --- a/tests/Browser/Dishes/CreateDishTest.php +++ b/tests/Browser/Dishes/CreateDishTest.php @@ -3,18 +3,18 @@ namespace Tests\Browser\Dishes; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\Pages\DishesPage; -use Tests\Browser\Components\DishModal; use Tests\Browser\LoginHelpers; +use Tests\Browser\Pages\DishesPage; +use Tests\DuskTestCase; class CreateDishTest extends DuskTestCase { use LoginHelpers; - + protected static $createDishTestPlanner = null; + protected static $createDishTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -22,7 +22,7 @@ protected function setUp(): void self::$testPlanner = self::$createDishTestPlanner; self::$testEmail = self::$createDishTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -30,18 +30,18 @@ protected function tearDown(): void self::$createDishTestEmail = self::$testEmail; parent::tearDown(); } - - public function testCanAccessDishesPage(): void + + public function test_can_access_dishes_page(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser); - + $browser->on(new DishesPage) - ->assertSee('MANAGE DISHES') - ->assertSee('Add Dish'); + ->assertSee('MANAGE DISHES') + ->assertSee('Add Dish'); }); } // TODO: Moved to separate single-method test files to avoid static planner issues // See: OpenCreateDishModalTest, CreateDishFormValidationTest, CancelDishCreationTest, CreateDishSuccessTest -} \ No newline at end of file +} diff --git a/tests/Browser/Dishes/DeleteDishTest.php b/tests/Browser/Dishes/DeleteDishTest.php index 51083f1..f0d7651 100644 --- a/tests/Browser/Dishes/DeleteDishTest.php +++ b/tests/Browser/Dishes/DeleteDishTest.php @@ -2,18 +2,19 @@ namespace Tests\Browser\Dishes; -use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\LoginHelpers; use App\Models\Planner; +use Laravel\Dusk\Browser; +use Tests\Browser\LoginHelpers; +use Tests\DuskTestCase; class DeleteDishTest extends DuskTestCase { use LoginHelpers; - + protected static $deleteDishTestPlanner = null; + protected static $deleteDishTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -21,7 +22,7 @@ protected function setUp(): void self::$testPlanner = self::$deleteDishTestPlanner; self::$testEmail = self::$deleteDishTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -29,14 +30,14 @@ protected function tearDown(): void self::$deleteDishTestEmail = self::$testEmail; parent::tearDown(); } - - public function testCanAccessDeleteFeature(): void + + public function test_can_access_delete_feature(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser) - ->assertPathIs('/dishes') - ->assertSee('MANAGE DISHES'); - + ->assertPathIs('/dishes') + ->assertSee('MANAGE DISHES'); + // Verify that delete functionality is available by looking for the text in the page source $pageSource = $browser->driver->getPageSource(); $this->assertStringContainsString('Delete', $pageSource); @@ -59,7 +60,7 @@ public function testDeletionSafetyFeatures(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser); - + // Check that Livewire component includes all CRUD features $pageSource = $browser->driver->getPageSource(); $this->assertStringContainsString('MANAGE DISHES', $pageSource); @@ -73,4 +74,4 @@ public function testDeletionSafetyFeatures(): void }); } */ -} \ No newline at end of file +} diff --git a/tests/Browser/Dishes/DishDeletionSafetyTest.php b/tests/Browser/Dishes/DishDeletionSafetyTest.php index ab5b1d2..70b030f 100644 --- a/tests/Browser/Dishes/DishDeletionSafetyTest.php +++ b/tests/Browser/Dishes/DishDeletionSafetyTest.php @@ -3,16 +3,17 @@ namespace Tests\Browser\Dishes; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; use Tests\Browser\LoginHelpers; +use Tests\DuskTestCase; class DishDeletionSafetyTest extends DuskTestCase { use LoginHelpers; - + protected static $dishDeletionSafetyTestPlanner = null; + protected static $dishDeletionSafetyTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -20,7 +21,7 @@ protected function setUp(): void self::$testPlanner = self::$dishDeletionSafetyTestPlanner; self::$testEmail = self::$dishDeletionSafetyTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -29,11 +30,11 @@ protected function tearDown(): void parent::tearDown(); } - public function testDeletionSafetyFeatures(): void + public function test_deletion_safety_features(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser); - + // Check that Livewire component includes all CRUD features $pageSource = $browser->driver->getPageSource(); $this->assertStringContainsString('MANAGE DISHES', $pageSource); @@ -46,4 +47,4 @@ public function testDeletionSafetyFeatures(): void } }); } -} \ No newline at end of file +} diff --git a/tests/Browser/Dishes/EditDishTest.php b/tests/Browser/Dishes/EditDishTest.php index af2d2f8..c27fec8 100644 --- a/tests/Browser/Dishes/EditDishTest.php +++ b/tests/Browser/Dishes/EditDishTest.php @@ -2,18 +2,19 @@ namespace Tests\Browser\Dishes; -use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\LoginHelpers; use App\Models\Planner; +use Laravel\Dusk\Browser; +use Tests\Browser\LoginHelpers; +use Tests\DuskTestCase; class EditDishTest extends DuskTestCase { use LoginHelpers; - + protected static $editDishTestPlanner = null; + protected static $editDishTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -21,7 +22,7 @@ protected function setUp(): void self::$testPlanner = self::$editDishTestPlanner; self::$testEmail = self::$editDishTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -29,36 +30,36 @@ protected function tearDown(): void self::$editDishTestEmail = self::$testEmail; parent::tearDown(); } - - public function testCanAccessEditFeature(): void + + public function test_can_access_edit_feature(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser) - ->assertPathIs('/dishes') - ->assertSee('MANAGE DISHES'); - + ->assertPathIs('/dishes') + ->assertSee('MANAGE DISHES'); + // Verify that edit functionality is available by looking for the text in the page source $pageSource = $browser->driver->getPageSource(); $this->assertStringContainsString('Edit', $pageSource); }); } - public function testEditModalComponents(): void + public function test_edit_modal_components(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser) - ->assertSee('MANAGE DISHES') - ->assertSee('Add Dish'); + ->assertSee('MANAGE DISHES') + ->assertSee('Add Dish'); }); } - public function testDishesPageStructure(): void + public function test_dishes_page_structure(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToDishes($browser) - ->assertSee('MANAGE DISHES') - ->assertSee('Add Dish'); - + ->assertSee('MANAGE DISHES') + ->assertSee('Add Dish'); + // Check that the dishes CRUD structure is present $pageSource = $browser->driver->getPageSource(); // Either we have dishes with Edit/Delete buttons OR "No dishes found" message @@ -70,4 +71,4 @@ public function testDishesPageStructure(): void } }); } -} \ No newline at end of file +} diff --git a/tests/Browser/LoginHelpers.php b/tests/Browser/LoginHelpers.php index 2d4aac2..cfed692 100644 --- a/tests/Browser/LoginHelpers.php +++ b/tests/Browser/LoginHelpers.php @@ -2,25 +2,29 @@ namespace Tests\Browser; +use App\Models\Planner; +use Illuminate\Support\Facades\Hash; use Laravel\Dusk\Browser; use Tests\DuskTestCase; trait LoginHelpers { protected static $testPlanner = null; + protected static $testEmail = null; + protected static $testPassword = 'password'; protected function ensureTestPlannerExists(): void { // Always create a fresh planner for each test class to avoid session conflicts - if (self::$testPlanner === null || !self::$testPlanner->exists) { + if (self::$testPlanner === null || ! self::$testPlanner->exists) { // Generate unique email for this test run self::$testEmail = fake()->unique()->safeEmail(); - - self::$testPlanner = \App\Models\Planner::factory()->create([ + + self::$testPlanner = Planner::factory()->create([ 'email' => self::$testEmail, - 'password' => \Illuminate\Support\Facades\Hash::make(self::$testPassword), + 'password' => Hash::make(self::$testPassword), ]); } } @@ -28,21 +32,21 @@ protected function ensureTestPlannerExists(): void protected function loginAndNavigate(Browser $browser, string $page = '/dashboard'): Browser { $this->ensureTestPlannerExists(); - + // Clear browser session and cookies to start fresh $browser->driver->manage()->deleteAllCookies(); - + return $browser->visit('http://dishplanner_app:8000/login') - ->waitFor('input[id="email"]', DuskTestCase::TIMEOUT_SHORT) - ->clear('input[id="email"]') - ->type('input[id="email"]', self::$testEmail) - ->clear('input[id="password"]') - ->type('input[id="password"]', self::$testPassword) - ->press('Sign In') - ->waitForLocation('/dashboard', DuskTestCase::TIMEOUT_MEDIUM) // Wait for successful login redirect - ->pause(DuskTestCase::PAUSE_SHORT) // Brief pause for any initialization - ->visit('http://dishplanner_app:8000' . $page) - ->pause(DuskTestCase::PAUSE_MEDIUM); // Let Livewire components initialize + ->waitFor('input[id="email"]', DuskTestCase::TIMEOUT_SHORT) + ->clear('input[id="email"]') + ->type('input[id="email"]', self::$testEmail) + ->clear('input[id="password"]') + ->type('input[id="password"]', self::$testPassword) + ->press('Sign In') + ->waitForLocation('/dashboard', DuskTestCase::TIMEOUT_MEDIUM) // Wait for successful login redirect + ->pause(DuskTestCase::PAUSE_SHORT) // Brief pause for any initialization + ->visit('http://dishplanner_app:8000'.$page) + ->pause(DuskTestCase::PAUSE_MEDIUM); // Let Livewire components initialize } protected function loginAndGoToDishes(Browser $browser): Browser diff --git a/tests/Browser/Pages/DishesPage.php b/tests/Browser/Pages/DishesPage.php index e8eeee5..ae5005f 100644 --- a/tests/Browser/Pages/DishesPage.php +++ b/tests/Browser/Pages/DishesPage.php @@ -20,7 +20,7 @@ public function url(): string public function assert(Browser $browser): void { $browser->assertPathIs($this->url()) - ->assertSee('MANAGE DISHES'); + ->assertSee('MANAGE DISHES'); } /** @@ -44,8 +44,8 @@ public function elements(): array public function openCreateModal(Browser $browser): void { $browser->waitFor('@add-button') - ->click('@add-button') - ->pause(1000); + ->click('@add-button') + ->pause(1000); } /** @@ -83,4 +83,4 @@ public function assertNoDishes(Browser $browser): void { $browser->assertSee('No dishes found'); } -} \ No newline at end of file +} diff --git a/tests/Browser/Pages/LoginPage.php b/tests/Browser/Pages/LoginPage.php index 6732270..d16642d 100644 --- a/tests/Browser/Pages/LoginPage.php +++ b/tests/Browser/Pages/LoginPage.php @@ -21,8 +21,8 @@ public function url(): string public function assert(Browser $browser): void { $browser->assertPathIs($this->url()) - ->assertSee('Login') - ->assertPresent((new LoginForm)->selector()); + ->assertSee('Login') + ->assertPresent((new LoginForm)->selector()); } /** @@ -44,4 +44,4 @@ public function goToRegistration(Browser $browser): void { $browser->click('@register-link'); } -} \ No newline at end of file +} diff --git a/tests/Browser/Pages/Page.php b/tests/Browser/Pages/Page.php index ecef801..54e0e22 100644 --- a/tests/Browser/Pages/Page.php +++ b/tests/Browser/Pages/Page.php @@ -18,4 +18,4 @@ public static function siteElements(): array '@alert' => '[role="alert"]', ]; } -} \ No newline at end of file +} diff --git a/tests/Browser/Pages/SchedulePage.php b/tests/Browser/Pages/SchedulePage.php index d2db379..bcd787f 100644 --- a/tests/Browser/Pages/SchedulePage.php +++ b/tests/Browser/Pages/SchedulePage.php @@ -14,7 +14,7 @@ public function url(): string public function assert(Browser $browser): void { $browser->assertPathIs($this->url()) - ->assertSee('SCHEDULE'); + ->assertSee('SCHEDULE'); } public function elements(): array @@ -34,49 +34,49 @@ public function elements(): array public function clickGenerate(Browser $browser): void { $browser->waitFor('@generate-button') - ->click('@generate-button') - ->pause(2000); // Wait for generation + ->click('@generate-button') + ->pause(2000); // Wait for generation } public function clickClearMonth(Browser $browser): void { $browser->waitFor('@clear-month-button') - ->click('@clear-month-button') - ->pause(1000); + ->click('@clear-month-button') + ->pause(1000); } public function goToPreviousMonth(Browser $browser): void { $browser->waitFor('@previous-month') - ->click('@previous-month') - ->pause(500); + ->click('@previous-month') + ->pause(500); } public function goToNextMonth(Browser $browser): void { $browser->waitFor('@next-month') - ->click('@next-month') - ->pause(500); + ->click('@next-month') + ->pause(500); } public function selectMonth(Browser $browser, int $month): void { $browser->waitFor('@month-select') - ->select('@month-select', $month) - ->pause(500); + ->select('@month-select', $month) + ->pause(500); } public function selectYear(Browser $browser, int $year): void { $browser->waitFor('@year-select') - ->select('@year-select', $year) - ->pause(500); + ->select('@year-select', $year) + ->pause(500); } public function toggleClearExisting(Browser $browser): void { $browser->waitFor('@clear-existing-checkbox') - ->click('@clear-existing-checkbox'); + ->click('@clear-existing-checkbox'); } public function selectUser(Browser $browser, string $userName): void @@ -84,7 +84,7 @@ public function selectUser(Browser $browser, string $userName): void $browser->check("input[type='checkbox'][value]", $userName); } - public function assertSuccessMessage(Browser $browser, string $message = null): void + public function assertSuccessMessage(Browser $browser, ?string $message = null): void { if ($message) { $browser->assertSee($message); diff --git a/tests/Browser/Pages/UsersPage.php b/tests/Browser/Pages/UsersPage.php index 71aed0a..7f0aa54 100644 --- a/tests/Browser/Pages/UsersPage.php +++ b/tests/Browser/Pages/UsersPage.php @@ -20,7 +20,7 @@ public function url(): string public function assert(Browser $browser): void { $browser->assertPathIs($this->url()) - ->assertSee('MANAGE USERS'); + ->assertSee('MANAGE USERS'); } /** @@ -43,8 +43,8 @@ public function elements(): array public function openCreateModal(Browser $browser): void { $browser->waitFor('@add-button') - ->click('@add-button') - ->pause(1000); + ->click('@add-button') + ->pause(1000); } /** @@ -63,8 +63,8 @@ public function clickDeleteForUser(Browser $browser, string $userName): void public function clickFirstDeleteButton(Browser $browser): void { $browser->waitFor('button.bg-danger', 5) - ->click('button.bg-danger') - ->pause(1000); + ->click('button.bg-danger') + ->pause(1000); } /** @@ -90,4 +90,4 @@ public function assertSuccessMessage(Browser $browser, string $message): void { $browser->assertSee($message); } -} \ No newline at end of file +} diff --git a/tests/Browser/RedirectTest.php b/tests/Browser/RedirectTest.php index 3c5954e..9b8913c 100644 --- a/tests/Browser/RedirectTest.php +++ b/tests/Browser/RedirectTest.php @@ -2,9 +2,9 @@ namespace Tests\Browser; +use Illuminate\Foundation\Testing\DatabaseTransactions; use Laravel\Dusk\Browser; use Tests\DuskTestCase; -use Illuminate\Foundation\Testing\DatabaseTransactions; class RedirectTest extends DuskTestCase { @@ -13,26 +13,26 @@ class RedirectTest extends DuskTestCase /** * Test that unauthenticated users are redirected to login */ - public function testUnauthenticatedRedirectsToLogin() + public function test_unauthenticated_redirects_to_login() { $this->browse(function (Browser $browser) { $browser->visit('http://dishplanner_app:8000/dashboard') - ->assertPathIs('/login') - ->assertSee('Login'); + ->assertPathIs('/login') + ->assertSee('Login'); }); } - + /** * Test that login page loads correctly */ - public function testLoginPageLoads() + public function test_login_page_loads() { $this->browse(function (Browser $browser) { $browser->visit('http://dishplanner_app:8000/login') - ->assertPathIs('/login') - ->assertSee('Login') - ->assertSee('Email') - ->assertSee('Password'); + ->assertPathIs('/login') + ->assertSee('Login') + ->assertSee('Email') + ->assertSee('Password'); }); } -} \ No newline at end of file +} diff --git a/tests/Browser/Schedule/GenerateScheduleTest.php b/tests/Browser/Schedule/GenerateScheduleTest.php index f3e945c..c2f1f71 100644 --- a/tests/Browser/Schedule/GenerateScheduleTest.php +++ b/tests/Browser/Schedule/GenerateScheduleTest.php @@ -7,15 +7,19 @@ use App\Models\User; use Illuminate\Support\Facades\Hash; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; use Tests\Browser\Pages\SchedulePage; +use Tests\DuskTestCase; class GenerateScheduleTest extends DuskTestCase { protected static $planner = null; + protected static $email = null; + protected static $password = 'password'; + protected static $user = null; + protected static $dish = null; protected function setUp(): void @@ -52,73 +56,73 @@ protected function loginAsPlanner(Browser $browser): Browser $browser->driver->manage()->deleteAllCookies(); return $browser->visit('http://dishplanner_app:8000/login') - ->waitFor('input[id="email"]', DuskTestCase::TIMEOUT_SHORT) - ->clear('input[id="email"]') - ->type('input[id="email"]', self::$email) - ->clear('input[id="password"]') - ->type('input[id="password"]', self::$password) - ->press('Login') - ->waitForLocation('/dashboard', DuskTestCase::TIMEOUT_MEDIUM) - ->pause(DuskTestCase::PAUSE_SHORT) - ->visit('http://dishplanner_app:8000/schedule') - ->pause(DuskTestCase::PAUSE_MEDIUM); + ->waitFor('input[id="email"]', DuskTestCase::TIMEOUT_SHORT) + ->clear('input[id="email"]') + ->type('input[id="email"]', self::$email) + ->clear('input[id="password"]') + ->type('input[id="password"]', self::$password) + ->press('Login') + ->waitForLocation('/dashboard', DuskTestCase::TIMEOUT_MEDIUM) + ->pause(DuskTestCase::PAUSE_SHORT) + ->visit('http://dishplanner_app:8000/schedule') + ->pause(DuskTestCase::PAUSE_MEDIUM); } - public function testCanGenerateScheduleWithUserAndDish(): void + public function test_can_generate_schedule_with_user_and_dish(): void { $this->browse(function (Browser $browser) { $this->loginAsPlanner($browser); $browser->on(new SchedulePage) - ->assertSee('Test User') // User should be in selection - ->clickGenerate() - ->pause(2000) + ->assertSee('Test User') // User should be in selection + ->clickGenerate() + ->pause(2000) // Verify schedule was generated by checking dish appears on calendar - ->assertSee('Test Dish'); + ->assertSee('Test Dish'); }); } - public function testGeneratedScheduleShowsDishOnCalendar(): void + public function test_generated_schedule_shows_dish_on_calendar(): void { $this->browse(function (Browser $browser) { $this->loginAsPlanner($browser); $browser->on(new SchedulePage) - ->clickGenerate() - ->pause(2000) + ->clickGenerate() + ->pause(2000) // The dish should appear somewhere on the calendar - ->assertSee('Test Dish'); + ->assertSee('Test Dish'); }); } - public function testCanClearMonthSchedule(): void + public function test_can_clear_month_schedule(): void { $this->browse(function (Browser $browser) { $this->loginAsPlanner($browser); $browser->on(new SchedulePage) // First generate a schedule - ->clickGenerate() - ->pause(2000) - ->assertSee('Test Dish') // Verify generated + ->clickGenerate() + ->pause(2000) + ->assertSee('Test Dish') // Verify generated // Then clear it - ->clickClearMonth() - ->pause(1000) + ->clickClearMonth() + ->pause(1000) // After clearing, should see "No dishes scheduled" on calendar days - ->assertSee('No dishes scheduled'); + ->assertSee('No dishes scheduled'); }); } - public function testUserSelectionAffectsGeneration(): void + public function test_user_selection_affects_generation(): void { $this->browse(function (Browser $browser) { $this->loginAsPlanner($browser); $browser->on(new SchedulePage) // Verify the user checkbox is present - ->assertSee('Test User') + ->assertSee('Test User') // User should be selected by default - ->assertChecked("input[value='" . self::$user->id . "']"); + ->assertChecked("input[value='".self::$user->id."']"); }); } } diff --git a/tests/Browser/Schedule/SchedulePageTest.php b/tests/Browser/Schedule/SchedulePageTest.php index a0a2ace..b4d59a0 100644 --- a/tests/Browser/Schedule/SchedulePageTest.php +++ b/tests/Browser/Schedule/SchedulePageTest.php @@ -3,15 +3,16 @@ namespace Tests\Browser\Schedule; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\Pages\SchedulePage; use Tests\Browser\LoginHelpers; +use Tests\Browser\Pages\SchedulePage; +use Tests\DuskTestCase; class SchedulePageTest extends DuskTestCase { use LoginHelpers; protected static $schedulePageTestPlanner = null; + protected static $schedulePageTestEmail = null; protected function setUp(): void @@ -28,30 +29,30 @@ protected function tearDown(): void parent::tearDown(); } - public function testCanAccessSchedulePage(): void + public function test_can_access_schedule_page(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToSchedule($browser); $browser->on(new SchedulePage) - ->assertSee('SCHEDULE') - ->assertSee('Generate Schedule'); + ->assertSee('SCHEDULE') + ->assertSee('Generate Schedule'); }); } - public function testSchedulePageHasMonthNavigation(): void + public function test_schedule_page_has_month_navigation(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToSchedule($browser); $browser->on(new SchedulePage) - ->assertPresent('@previous-month') - ->assertPresent('@next-month') - ->assertSee(now()->format('F Y')); + ->assertPresent('@previous-month') + ->assertPresent('@next-month') + ->assertSee(now()->format('F Y')); }); } - public function testCanNavigateToNextMonth(): void + public function test_can_navigate_to_next_month(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToSchedule($browser); @@ -59,12 +60,12 @@ public function testCanNavigateToNextMonth(): void $nextMonth = now()->addMonth(); $browser->on(new SchedulePage) - ->goToNextMonth() - ->assertSee($nextMonth->format('F Y')); + ->goToNextMonth() + ->assertSee($nextMonth->format('F Y')); }); } - public function testCanNavigateToPreviousMonth(): void + public function test_can_navigate_to_previous_month(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToSchedule($browser); @@ -72,36 +73,36 @@ public function testCanNavigateToPreviousMonth(): void $prevMonth = now()->subMonth(); $browser->on(new SchedulePage) - ->goToPreviousMonth() - ->assertSee($prevMonth->format('F Y')); + ->goToPreviousMonth() + ->assertSee($prevMonth->format('F Y')); }); } - public function testScheduleGeneratorShowsUserSelection(): void + public function test_schedule_generator_shows_user_selection(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToSchedule($browser); $browser->on(new SchedulePage) - ->assertSee('Select Users') - ->assertPresent('@generate-button') - ->assertPresent('@clear-month-button'); + ->assertSee('Select Users') + ->assertPresent('@generate-button') + ->assertPresent('@clear-month-button'); }); } - public function testCalendarDisplaysDaysOfWeek(): void + public function test_calendar_displays_days_of_week(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToSchedule($browser); $browser->on(new SchedulePage) - ->assertSee('Mon') - ->assertSee('Tue') - ->assertSee('Wed') - ->assertSee('Thu') - ->assertSee('Fri') - ->assertSee('Sat') - ->assertSee('Sun'); + ->assertSee('Mon') + ->assertSee('Tue') + ->assertSee('Wed') + ->assertSee('Thu') + ->assertSee('Fri') + ->assertSee('Sat') + ->assertSee('Sun'); }); } } diff --git a/tests/Browser/Users/CreateUserTest.php b/tests/Browser/Users/CreateUserTest.php index 56ebbb3..6817560 100644 --- a/tests/Browser/Users/CreateUserTest.php +++ b/tests/Browser/Users/CreateUserTest.php @@ -3,17 +3,18 @@ namespace Tests\Browser\Users; use Laravel\Dusk\Browser; -use Tests\DuskTestCase; -use Tests\Browser\Pages\UsersPage; use Tests\Browser\LoginHelpers; +use Tests\Browser\Pages\UsersPage; +use Tests\DuskTestCase; class CreateUserTest extends DuskTestCase { use LoginHelpers; - + protected static $createUserTestPlanner = null; + protected static $createUserTestEmail = null; - + protected function setUp(): void { parent::setUp(); @@ -21,7 +22,7 @@ protected function setUp(): void self::$testPlanner = self::$createUserTestPlanner; self::$testEmail = self::$createUserTestEmail; } - + protected function tearDown(): void { // Save the planner for next test method in this class @@ -30,74 +31,74 @@ protected function tearDown(): void parent::tearDown(); } - public function testCanAccessUsersPage(): void + public function test_can_access_users_page(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToUsers($browser); - + $browser->on(new UsersPage) - ->assertSee('MANAGE USERS') - ->assertSee('Add User'); + ->assertSee('MANAGE USERS') + ->assertSee('Add User'); }); } - public function testCanOpenCreateUserModal(): void + public function test_can_open_create_user_modal(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToUsers($browser); $browser->on(new UsersPage) - ->openCreateModal() - ->assertSee('Add New User') - ->assertSee('Name') - ->assertSee('Cancel') - ->assertSee('Create User'); + ->openCreateModal() + ->assertSee('Add New User') + ->assertSee('Name') + ->assertSee('Cancel') + ->assertSee('Create User'); }); } - public function testCreateUserFormValidation(): void + public function test_create_user_form_validation(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToUsers($browser); $browser->on(new UsersPage) - ->openCreateModal() - ->press('Create User') - ->pause(self::PAUSE_MEDIUM) - ->assertSee('The name field is required'); + ->openCreateModal() + ->press('Create User') + ->pause(self::PAUSE_MEDIUM) + ->assertSee('The name field is required'); }); } - public function testCanCreateUser(): void + public function test_can_create_user(): void { $this->browse(function (Browser $browser) { - $userName = 'TestCreate_' . uniqid(); + $userName = 'TestCreate_'.uniqid(); $this->loginAndGoToUsers($browser); $browser->on(new UsersPage) - ->openCreateModal() - ->type('input[wire\\:model="name"]', $userName) - ->press('Create User') - ->pause(self::PAUSE_MEDIUM) - ->assertSee('User created successfully') - ->assertSee($userName); + ->openCreateModal() + ->type('input[wire\\:model="name"]', $userName) + ->press('Create User') + ->pause(self::PAUSE_MEDIUM) + ->assertSee('User created successfully') + ->assertSee($userName); }); } - public function testCanCancelUserCreation(): void + public function test_can_cancel_user_creation(): void { $this->browse(function (Browser $browser) { $this->loginAndGoToUsers($browser); $browser->on(new UsersPage) - ->openCreateModal() - ->type('input[wire\\:model="name"]', 'Test Cancel User') - ->press('Cancel') - ->pause(self::PAUSE_SHORT) + ->openCreateModal() + ->type('input[wire\\:model="name"]', 'Test Cancel User') + ->press('Cancel') + ->pause(self::PAUSE_SHORT) // Modal should be closed, we should be back on users page - ->assertSee('MANAGE USERS') - ->assertDontSee('Add New User'); + ->assertSee('MANAGE USERS') + ->assertDontSee('Add New User'); }); } -} \ No newline at end of file +} diff --git a/tests/DuskTestCase.php b/tests/DuskTestCase.php index ec8f947..075cf58 100644 --- a/tests/DuskTestCase.php +++ b/tests/DuskTestCase.php @@ -5,7 +5,6 @@ use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; -use Illuminate\Support\Collection; use Laravel\Dusk\TestCase as BaseTestCase; use PHPUnit\Framework\Attributes\BeforeClass; @@ -13,8 +12,11 @@ abstract class DuskTestCase extends BaseTestCase { // Timeout constants for consistent timing across all Dusk tests public const TIMEOUT_SHORT = 2; // 2 seconds max for most operations + public const TIMEOUT_MEDIUM = 3; // 3 seconds for slower operations + public const PAUSE_SHORT = 500; // 0.5 seconds for quick pauses + public const PAUSE_MEDIUM = 1000; // 1 second for medium pauses /** diff --git a/tests/Feature/AuthenticationTest.php b/tests/Feature/AuthenticationTest.php index e6486f4..ff3ebb7 100644 --- a/tests/Feature/AuthenticationTest.php +++ b/tests/Feature/AuthenticationTest.php @@ -2,10 +2,10 @@ namespace Tests\Feature; -use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; -use Tests\TestCase; use App\Models\Planner; +use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; class AuthenticationTest extends TestCase { @@ -61,10 +61,6 @@ public function test_session_is_created_on_login_page(): void // Check if CSRF token is generated $this->assertNotNull(csrf_token()); - // Check session driver - $sessionDriver = config('session.driver'); - $this->assertNotEquals('array', $sessionDriver, 'Session driver should not be array for authentication'); - $response->assertStatus(200); $response->assertSessionHasNoErrors(); } diff --git a/tests/Feature/Dish/CreateDishTest.php b/tests/Feature/Dish/CreateDishTest.php index 8733917..54a4e21 100755 --- a/tests/Feature/Dish/CreateDishTest.php +++ b/tests/Feature/Dish/CreateDishTest.php @@ -3,7 +3,6 @@ namespace Tests\Feature\Dish; use App\Models\Dish; -use App\Models\Planner; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Str; use Illuminate\Testing\Fluent\AssertableJson; diff --git a/tests/Feature/Dish/DeleteDishTest.php b/tests/Feature/Dish/DeleteDishTest.php index b773776..b07fde6 100644 --- a/tests/Feature/Dish/DeleteDishTest.php +++ b/tests/Feature/Dish/DeleteDishTest.php @@ -64,7 +64,6 @@ public function test_it_deletes_user_dishes_when_deleting_a_dish(): void $this->assertDatabaseEmpty(UserDish::class); } - public function test_planner_cannot_delete_dish_from_other_planner(): void { $planner = $this->planner; diff --git a/tests/Feature/RegistrationTest.php b/tests/Feature/RegistrationTest.php index b68a311..8908407 100644 --- a/tests/Feature/RegistrationTest.php +++ b/tests/Feature/RegistrationTest.php @@ -2,9 +2,9 @@ namespace Tests\Feature; -use Tests\TestCase; use App\Models\Planner; use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\TestCase; class RegistrationTest extends TestCase { @@ -13,7 +13,7 @@ class RegistrationTest extends TestCase public function test_registration_screen_can_be_rendered() { $response = $this->get('/register'); - + $response->assertStatus(200); $response->assertViewIs('auth.register'); $response->assertSee('Register'); @@ -30,7 +30,7 @@ public function test_new_users_can_register() $this->assertAuthenticated(); $response->assertRedirect('/dashboard'); - + // Check user was created $this->assertDatabaseHas('planners', [ 'email' => 'test@example.com', @@ -68,10 +68,10 @@ public function test_registration_fails_with_password_mismatch() $response->assertRedirect(); $response->assertSessionHasErrors('password'); $this->assertGuest(); - + // Check user was not created $this->assertDatabaseMissing('planners', [ 'email' => 'test@example.com', ]); } -} \ No newline at end of file +} diff --git a/tests/Feature/Schedule/GenerateScheduleTest.php b/tests/Feature/Schedule/GenerateScheduleTest.php index 79bd6f6..d2fcd1e 100644 --- a/tests/Feature/Schedule/GenerateScheduleTest.php +++ b/tests/Feature/Schedule/GenerateScheduleTest.php @@ -3,12 +3,11 @@ namespace Tests\Feature\Schedule; use App\Models\Dish; -use App\Models\Planner; -use App\Models\UserDish; -use App\Models\UserDishRecurrence; use App\Models\Schedule; use App\Models\ScheduledUserDish; use App\Models\User; +use App\Models\UserDish; +use App\Models\UserDishRecurrence; use App\Models\WeeklyRecurrence; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Carbon; @@ -115,6 +114,7 @@ public function test_fresh_schedule_adheres_to_fixed_recurrences(): void $this->assertContains($targetUserDish->id, $targetScheduledUserDishes); } + public function test_schedule_can_be_overwritten(): void { $planner = $this->planner; @@ -132,8 +132,7 @@ public function test_schedule_can_be_overwritten(): void }); // Assert that every user has `UserDish` records - $users->each(fn (User $user) => - $this->assertNotEmpty($user->refresh()->userDishes) + $users->each(fn (User $user) => $this->assertNotEmpty($user->refresh()->userDishes) ); $scheduleDay = Schedule::factory() @@ -172,7 +171,7 @@ public function test_schedule_can_be_overwritten(): void $this->assertDatabaseCount(Schedule::class, 14); - $freshScheduleDay = Schedule::query()->where('date', $scheduleDay->date)->first(); + $freshScheduleDay = Schedule::query()->whereDate('date', $scheduleDay->date)->first(); $this->assertNotEquals( $originalUserDishes, $freshScheduleDay->scheduledUserDishes->map(fn (ScheduledUserDish $scheduledUserDish) => [ @@ -218,11 +217,11 @@ public function test_fixed_recurrence_takes_precedence_during_overwrite(): void $users ->map(fn (User $user) => ScheduledUserDish::factory() - ->create([ - 'schedule_id' => $scheduleDay->id, - 'user_dish_id' => $user->userDishes->random()->id, - 'user_id' => $user->id, - ])); + ->create([ + 'schedule_id' => $scheduleDay->id, + 'user_dish_id' => $user->userDishes->random()->id, + 'user_id' => $user->id, + ])); ScheduledUserDish::factory() ->schedule($scheduleDay) @@ -235,7 +234,6 @@ public function test_fixed_recurrence_takes_precedence_during_overwrite(): void $this->assertDatabaseCount(Schedule::class, 1); $this->assertDatabaseCount(ScheduledUserDish::class, 2); - $this ->actingAs($planner) ->post(route('api.schedule.generate'), [ diff --git a/tests/Feature/Schedule/ListScheduleTest.php b/tests/Feature/Schedule/ListScheduleTest.php index 4f24cb1..2168c6d 100644 --- a/tests/Feature/Schedule/ListScheduleTest.php +++ b/tests/Feature/Schedule/ListScheduleTest.php @@ -38,6 +38,7 @@ public function test_full_calendar_dishes_list_for_a_given_date_range(): void $schedule = Schedule::factory()->planner($planner)->date($date)->create(); $users->each(function (User $user) use ($schedule) { $randomUserDish = $user->userDishes->random(); + return $schedule->scheduledUserDishes()->create([ 'user_dish_id' => $randomUserDish->id, 'user_id' => $randomUserDish->user->id, @@ -80,6 +81,7 @@ public function test_it_does_not_show_dishes_of_other_planner(): void $schedule = Schedule::factory()->planner($otherPlanner)->date($date)->create(); $users->each(function (User $user) use ($schedule) { $randomUserDish = $user->userDishes->random(); + return $schedule->scheduledUserDishes()->create([ 'user_dish_id' => $randomUserDish->id, 'user_id' => $randomUserDish->user->id, diff --git a/tests/Feature/Schedule/UpdateScheduleTest.php b/tests/Feature/Schedule/UpdateScheduleTest.php index 1d770b6..d60e367 100644 --- a/tests/Feature/Schedule/UpdateScheduleTest.php +++ b/tests/Feature/Schedule/UpdateScheduleTest.php @@ -33,11 +33,11 @@ public function test_user_can_mark_day_as_skipped(): void $dishes->each(fn (Dish $dish) => $dish->users()->attach($users)); ScheduledUserDish::factory() ->schedule($schedule) - ->userDish($dishes->random()->userDishes->random()) + ->userDish($userOne->userDishes->firstOrFail()) ->create([]); ScheduledUserDish::factory() ->schedule($schedule) - ->userDish($dishes->random()->userDishes->random()) + ->userDish($userTwo->userDishes->firstOrFail()) ->create([]); $schedule->refresh(); diff --git a/tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php b/tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php index 67626de..04caad3 100644 --- a/tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php +++ b/tests/Feature/ScheduledUserDish/CreateScheduledUserDishTest.php @@ -75,7 +75,6 @@ public function test_planner_can_schedule_user_dishes(): void ->where('errors', null) ); - $this->assertDatabaseCount(Schedule::class, 1); $this->assertDatabaseHas(Schedule::class, [ 'date' => $scheduleDate, @@ -116,11 +115,10 @@ public function test_planner_cannot_schedule_user_dishes_from_other_planner(): v ->where('success', false) ->whereNull('payload') ->where('errors', [ - "This action is unauthorized." + 'This action is unauthorized.', ]) ); - $this->assertDatabaseEmpty(Schedule::class); $this->assertDatabaseEmpty(ScheduledUserDish::class); } diff --git a/tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php b/tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php index 4527623..ad6194f 100755 --- a/tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php +++ b/tests/Feature/ScheduledUserDish/DeleteScheduledUserDishTest.php @@ -79,7 +79,7 @@ public function test_planner_cannot_delete_a_scheduled_dish_of_another_planner() ->where('success', false) ->where('payload', null) ->where('errors', [ - "This action is unauthorized." + 'This action is unauthorized.', ]) ); diff --git a/tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php b/tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php index 5571d3f..6c7f5e4 100644 --- a/tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php +++ b/tests/Feature/ScheduledUserDish/ReadScheduledUserDishTest.php @@ -129,7 +129,7 @@ public function test_planner_cannot_read_scheduled_user_dish_from_other_planner( ->where('success', false) ->where('payload', null) ->where('errors', [ - "This action is unauthorized." + 'This action is unauthorized.', ]) ); } diff --git a/tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php b/tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php index 68953dc..6a00c5d 100644 --- a/tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php +++ b/tests/Feature/ScheduledUserDish/UpdateScheduledUserDishTest.php @@ -16,9 +16,9 @@ class UpdateScheduledUserDishTest extends TestCase { + use DishesTestTrait; use HasPlanner; use RefreshDatabase; - use DishesTestTrait; use ScheduledDishesTestTrait; protected function setUp(): void @@ -126,7 +126,7 @@ public function test_planner_cannot_update_dish_of_other_planner(): void ->where('success', false) ->where('payload', null) ->where('errors', [ - "This action is unauthorized." + 'This action is unauthorized.', ]) ); } diff --git a/tests/Feature/User/CreateUserTest.php b/tests/Feature/User/CreateUserTest.php index 76be687..7eaca58 100644 --- a/tests/Feature/User/CreateUserTest.php +++ b/tests/Feature/User/CreateUserTest.php @@ -2,7 +2,6 @@ namespace Tests\Feature\User; -use App\Models\Planner; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Testing\Fluent\AssertableJson; diff --git a/tests/Feature/User/DeleteUserTest.php b/tests/Feature/User/DeleteUserTest.php index b67e55d..7acfac6 100644 --- a/tests/Feature/User/DeleteUserTest.php +++ b/tests/Feature/User/DeleteUserTest.php @@ -52,7 +52,7 @@ public function test_planner_cannot_update_user_of_other_planner(): void ->assertJson(fn (AssertableJson $json) => $json ->where('success', false) ->where('payload', null) - ->where('errors', ["MODEL_NOT_FOUND"]) + ->where('errors', ['MODEL_NOT_FOUND']) ); } } diff --git a/tests/Feature/User/Dish/ListUserDishesTest.php b/tests/Feature/User/Dish/ListUserDishesTest.php index 8515193..a2dd542 100644 --- a/tests/Feature/User/Dish/ListUserDishesTest.php +++ b/tests/Feature/User/Dish/ListUserDishesTest.php @@ -5,7 +5,6 @@ use App\Models\Dish; use App\Models\Planner; use App\Models\User; -use App\Models\UserDish; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Testing\Fluent\AssertableJson; use Tests\TestCase; @@ -62,5 +61,4 @@ public function test_planner_cannot_see_user_dishes_from_other_planner(): void ->where('errors', null) ); } - } diff --git a/tests/Feature/User/Dish/RemoveDishesForUserTest.php b/tests/Feature/User/Dish/RemoveDishesForUserTest.php index 2f7e15a..6dce0f4 100755 --- a/tests/Feature/User/Dish/RemoveDishesForUserTest.php +++ b/tests/Feature/User/Dish/RemoveDishesForUserTest.php @@ -36,7 +36,7 @@ public function test_it_can_remove_dish_for_a_user(): void ->actingAs($planner) ->delete(route('api.users.dishes.destroy', [ 'dish' => $dish, - 'user' => $user + 'user' => $user, ]), []) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json diff --git a/tests/Feature/User/Dish/ShowUserDishTest.php b/tests/Feature/User/Dish/ShowUserDishTest.php index b1e294f..1c75afa 100644 --- a/tests/Feature/User/Dish/ShowUserDishTest.php +++ b/tests/Feature/User/Dish/ShowUserDishTest.php @@ -5,7 +5,6 @@ use App\Models\Dish; use App\Models\Planner; use App\Models\User; -use App\Models\UserDish; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Testing\Fluent\AssertableJson; use Tests\TestCase; diff --git a/tests/Feature/User/Dish/StoreRecurrenceForUserDishTest.php b/tests/Feature/User/Dish/StoreRecurrenceForUserDishTest.php index 205f634..673db96 100755 --- a/tests/Feature/User/Dish/StoreRecurrenceForUserDishTest.php +++ b/tests/Feature/User/Dish/StoreRecurrenceForUserDishTest.php @@ -62,7 +62,7 @@ public function test_it_adds_fixed_recurrence_to_user_dish(): void ->has('id') ->where('type', $recurrenceType) ->where('value', $recurrenceValue) - ) + ) ) ) ->where('errors', null) @@ -85,12 +85,12 @@ public function test_it_adds_minimum_recurrence_to_user_dish(): void ->actingAs($planner) ->post(route('api.users.dishes.recurrences.store', [ 'dish' => $dish, - 'user' => $user + 'user' => $user, ]), [ [ 'type' => $recurrenceType, 'value' => $recurrenceValue, - ] + ], ]) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json @@ -128,16 +128,16 @@ public function test_it_adds_multiple_recurrences_to_user_dish(): void ->actingAs($planner) ->post(route('api.users.dishes.recurrences.store', [ 'dish' => $dish, - 'user' => $user + 'user' => $user, ]), [ - [ - 'type' => MinimumRecurrence::class, - 'value' => 5, - ], - [ - 'type' => WeeklyRecurrence::class, - 'value' => WeekdaysEnum::Thursday->value, - ], + [ + 'type' => MinimumRecurrence::class, + 'value' => 5, + ], + [ + 'type' => WeeklyRecurrence::class, + 'value' => WeekdaysEnum::Thursday->value, + ], ]) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json @@ -187,7 +187,7 @@ public function test_it_removes_all_recurrences(): void ->actingAs($planner) ->post(route('api.users.dishes.recurrences.store', [ 'dish' => $dish, - 'user' => $user + 'user' => $user, ]), []) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json @@ -241,7 +241,7 @@ public function test_it_removes_other_recurrences_to_user_dish(): void ->actingAs($planner) ->post(route('api.users.dishes.recurrences.store', [ 'dish' => $dish, - 'user' => $user + 'user' => $user, ]), [ [ 'type' => WeeklyRecurrence::class, diff --git a/tests/Feature/User/UpdateUserTest.php b/tests/Feature/User/UpdateUserTest.php index 20c5e20..27f5f77 100644 --- a/tests/Feature/User/UpdateUserTest.php +++ b/tests/Feature/User/UpdateUserTest.php @@ -60,7 +60,7 @@ public function test_planner_cannot_update_user_of_other_planner(): void ->assertJson(fn (AssertableJson $json) => $json ->where('success', false) ->where('payload', null) - ->where('errors', ["MODEL_NOT_FOUND"]) + ->where('errors', ['MODEL_NOT_FOUND']) ); } } diff --git a/tests/Traits/DishesTestTrait.php b/tests/Traits/DishesTestTrait.php index 29d330d..a3475ee 100644 --- a/tests/Traits/DishesTestTrait.php +++ b/tests/Traits/DishesTestTrait.php @@ -9,7 +9,7 @@ trait DishesTestTrait { - public function generateDishes(Planner $planner, int $count = null): Collection + public function generateDishes(Planner $planner, ?int $count = null): Collection { if (is_null($count)) { $count = rand(15, 20); diff --git a/tests/Traits/ScheduledDishesTestTrait.php b/tests/Traits/ScheduledDishesTestTrait.php index 0690289..4a0026b 100644 --- a/tests/Traits/ScheduledDishesTestTrait.php +++ b/tests/Traits/ScheduledDishesTestTrait.php @@ -30,11 +30,11 @@ public function generateScheduledDishes(Planner $planner, ?CarbonPeriod $period $users ->each(fn (User $user) => ScheduledUserDish::factory() - ->schedule($schedule) - ->user($user) - ->userDish($user->userDishes->random()) - ->create() - ); + ->schedule($schedule) + ->user($user) + ->userDish($user->userDishes->random()) + ->create() + ); }); } } diff --git a/tests/Unit/Actions/EditUserActionTest.php b/tests/Unit/Actions/EditUserActionTest.php index 464cca9..6e0b543 100644 --- a/tests/Unit/Actions/EditUserActionTest.php +++ b/tests/Unit/Actions/EditUserActionTest.php @@ -25,7 +25,7 @@ protected function setUp(): void $planner = Planner::factory()->create(); $this->planner = $planner; - $this->action = new EditUserAction(); + $this->action = new EditUserAction; } public function test_successfully_updates_user_name(): void diff --git a/tests/Unit/Actions/RegenerateScheduleDayActionTest.php b/tests/Unit/Actions/RegenerateScheduleDayActionTest.php index c451b8c..d13898f 100644 --- a/tests/Unit/Actions/RegenerateScheduleDayActionTest.php +++ b/tests/Unit/Actions/RegenerateScheduleDayActionTest.php @@ -13,9 +13,9 @@ class RegenerateScheduleDayActionTest extends TestCase { + use DishesTestTrait; use HasPlanner; use RefreshDatabase; - use DishesTestTrait; protected function setUp(): void { @@ -36,7 +36,6 @@ public function test_it_regenerates_for_a_single_schedule(): void $mockAction = $this->mock(RegenerateScheduleDayForUserAction::class); $mockAction->shouldReceive('execute')->times(10); - resolve(RegenerateScheduleDayAction::class)->execute($planner, $schedule, true); } } diff --git a/tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php b/tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php index 6facf19..1a35c3b 100644 --- a/tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php +++ b/tests/Unit/Actions/RegenerateScheduleDayForUserActionTest.php @@ -34,10 +34,8 @@ public function test_it_creates(): void $this->assertEmpty($schedule->scheduledUserDishes); - resolve(RegenerateScheduleDayForUserAction::class)->execute($planner, $schedule, $user, true); - $expectedSchedule = Schedule::where('date', $date->format('Y-m-d'))->first(); $this->assertCount(1, $expectedSchedule->scheduledUserDishes); @@ -64,10 +62,8 @@ public function test_it_updates_if_overwrite_is_true(): void $this->assertCount(1, $schedule->refresh()->scheduledUserDishes); - resolve(RegenerateScheduleDayForUserAction::class)->execute($planner, $schedule, $user, true); - $schedule->refresh(); $this->assertCount(1, $schedule->scheduledUserDishes); @@ -95,10 +91,8 @@ public function test_it_does_not_update_if_overwrite_is_false(): void $this->assertCount(1, $schedule->refresh()->scheduledUserDishes); - resolve(RegenerateScheduleDayForUserAction::class)->execute($planner, $schedule, $user, false); - $schedule->refresh(); $this->assertCount(1, $schedule->scheduledUserDishes); diff --git a/tests/Unit/Actions/User/CreateUserActionTest.php b/tests/Unit/Actions/User/CreateUserActionTest.php index f899a58..d2247fa 100644 --- a/tests/Unit/Actions/User/CreateUserActionTest.php +++ b/tests/Unit/Actions/User/CreateUserActionTest.php @@ -14,13 +14,14 @@ class CreateUserActionTest extends TestCase use RefreshDatabase; private CreateUserAction $action; + private Planner $planner; protected function setUp(): void { parent::setUp(); - $this->action = new CreateUserAction(); - + $this->action = new CreateUserAction; + // Create a planner for testing $this->planner = Planner::factory()->create(); } @@ -58,9 +59,9 @@ public function test_it_throws_exception_when_name_is_empty(): void // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Name is required'); - + $this->action->execute($userData); - + // Verify no user was created $this->assertDatabaseMissing('users', [ 'planner_id' => $this->planner->id, @@ -77,7 +78,7 @@ public function test_it_throws_exception_when_name_is_missing(): void // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Name is required'); - + $this->action->execute($userData); } @@ -92,7 +93,7 @@ public function test_it_throws_exception_when_planner_id_is_empty(): void // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Planner ID is required'); - + $this->action->execute($userData); } @@ -106,7 +107,7 @@ public function test_it_throws_exception_when_planner_id_is_missing(): void // Act & Assert $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Planner ID is required'); - + $this->action->execute($userData); } @@ -128,13 +129,19 @@ public function test_it_logs_creation_process(): void 'name' => 'Test User', 'planner_id' => $this->planner->id, ]); - + Log::shouldHaveReceived('info') ->with('CreateUserAction: User successfully created', [ 'user_id' => $user->id, 'name' => 'Test User', 'planner_id' => $this->planner->id, ]); + + $this->assertDatabaseHas('users', [ + 'id' => $user->id, + 'name' => 'Test User', + 'planner_id' => $this->planner->id, + ]); } public function test_it_handles_database_transaction_rollback_on_failure(): void @@ -147,7 +154,7 @@ public function test_it_handles_database_transaction_rollback_on_failure(): void // Act & Assert $this->expectException(\Exception::class); - + try { $this->action->execute($userData); } catch (\Exception $e) { @@ -174,15 +181,17 @@ public function test_it_logs_errors_on_failure(): void } catch (\Exception $e) { // Expected } - + // Assert Log::shouldHaveReceived('error') ->with('CreateUserAction: User creation failed', \Mockery::on(function ($data) { - return $data['name'] === 'Test User' && + return $data['name'] === 'Test User' && $data['planner_id'] === 999999 && isset($data['error']) && isset($data['trace']); })); + + $this->assertDatabaseMissing('users', ['name' => 'Test User']); } public function test_it_creates_user_with_whitespace_trimmed_name(): void @@ -212,7 +221,7 @@ public function test_it_can_create_multiple_users_with_same_planner(): void 'name' => 'User One', 'planner_id' => $this->planner->id, ]; - + $userData2 = [ 'name' => 'User Two', 'planner_id' => $this->planner->id, @@ -235,4 +244,4 @@ protected function tearDown(): void \Mockery::close(); parent::tearDown(); } -} \ No newline at end of file +} diff --git a/tests/Unit/Actions/User/DeleteUserActionTest.php b/tests/Unit/Actions/User/DeleteUserActionTest.php index 1363176..9fd46aa 100644 --- a/tests/Unit/Actions/User/DeleteUserActionTest.php +++ b/tests/Unit/Actions/User/DeleteUserActionTest.php @@ -16,13 +16,14 @@ class DeleteUserActionTest extends TestCase use RefreshDatabase; private DeleteUserAction $action; + private Planner $planner; protected function setUp(): void { parent::setUp(); - $this->action = new DeleteUserAction(); - + $this->action = new DeleteUserAction; + // Create a planner for testing $this->planner = Planner::factory()->create(); } @@ -32,7 +33,7 @@ public function test_it_can_delete_a_user_successfully(): void // Arrange $user = User::factory()->create([ 'planner_id' => $this->planner->id, - 'name' => 'Test User' + 'name' => 'Test User', ]); $userId = $user->id; @@ -49,19 +50,19 @@ public function test_it_can_delete_a_user_with_associated_dishes(): void // Arrange $user = User::factory()->create(['planner_id' => $this->planner->id]); $dish = Dish::factory()->create(['planner_id' => $this->planner->id]); - + // Associate user with dish UserDish::create([ 'user_id' => $user->id, - 'dish_id' => $dish->id + 'dish_id' => $dish->id, ]); - + $userId = $user->id; - + // Verify the association exists $this->assertDatabaseHas('user_dishes', [ 'user_id' => $userId, - 'dish_id' => $dish->id + 'dish_id' => $dish->id, ]); // Act @@ -94,19 +95,21 @@ public function test_it_logs_deletion_process(): void 'user_name' => $userName, 'planner_id' => $this->planner->id, ]); - + Log::shouldHaveReceived('info') ->with('DeleteUserAction: User successfully deleted', [ 'user_id' => $userId, 'user_name' => $userName, ]); + + $this->assertDatabaseMissing('users', ['id' => $userId]); } public function test_it_handles_database_transaction_rollback_on_failure(): void { // Arrange $user = User::factory()->create(['planner_id' => $this->planner->id]); - + // Mock the user to throw an exception during deletion $mockUser = \Mockery::mock(User::class); $mockUser->shouldReceive('getAttribute')->with('id')->andReturn($user->id); @@ -119,9 +122,9 @@ public function test_it_handles_database_transaction_rollback_on_failure(): void // Act & Assert $this->expectException(\Exception::class); $this->expectExceptionMessage('Database error'); - + $this->action->execute($mockUser); - + // Verify original user still exists (transaction rolled back) $this->assertDatabaseHas('users', ['id' => $user->id]); } @@ -130,7 +133,7 @@ public function test_it_throws_exception_when_deletion_returns_false(): void { // Arrange $user = User::factory()->create(['planner_id' => $this->planner->id]); - + // Mock the user to return false on delete $mockUser = \Mockery::mock(User::class); $mockUser->shouldReceive('getAttribute')->with('id')->andReturn($user->id); @@ -143,13 +146,13 @@ public function test_it_throws_exception_when_deletion_returns_false(): void // Act & Assert $this->expectException(\Exception::class); $this->expectExceptionMessage('User deletion returned false'); - + $this->action->execute($mockUser); } public function test_it_throws_exception_when_deletion_does_not_persist(): void { - // This test is tricky to implement realistically since we can't easily + // This test is tricky to implement realistically since we can't easily // mock the User::find() call in a way that makes sense. // We'll skip this edge case for now, but in a real scenario you might // want to test database connection issues, etc. @@ -161,7 +164,7 @@ public function test_it_logs_errors_on_failure(): void // Arrange Log::spy(); $user = User::factory()->create(['planner_id' => $this->planner->id]); - + // Mock the user to throw an exception during deletion $mockUser = \Mockery::mock(User::class); $mockUser->shouldReceive('getAttribute')->with('id')->andReturn($user->id); @@ -177,14 +180,16 @@ public function test_it_logs_errors_on_failure(): void } catch (\Exception $e) { // Expected } - + // Assert Log::shouldHaveReceived('error') ->with('DeleteUserAction: User deletion failed', \Mockery::on(function ($data) use ($user) { - return $data['user_id'] === $user->id && + return $data['user_id'] === $user->id && $data['error'] === 'Test error' && isset($data['trace']); })); + + $this->assertDatabaseHas('users', ['id' => $user->id]); } protected function tearDown(): void @@ -192,4 +197,4 @@ protected function tearDown(): void \Mockery::close(); parent::tearDown(); } -} \ No newline at end of file +} diff --git a/tests/Unit/Actions/UserActionIntegrationTest.php b/tests/Unit/Actions/UserActionIntegrationTest.php index d5daa2d..f4aef83 100644 --- a/tests/Unit/Actions/UserActionIntegrationTest.php +++ b/tests/Unit/Actions/UserActionIntegrationTest.php @@ -4,6 +4,7 @@ use App\Actions\User\CreateUserAction; use App\Actions\User\DeleteUserAction; +use App\Models\Dish; use App\Models\Planner; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -14,16 +15,18 @@ class UserActionIntegrationTest extends TestCase use RefreshDatabase; private Planner $planner; + private CreateUserAction $createAction; + private DeleteUserAction $deleteAction; protected function setUp(): void { parent::setUp(); - + $this->planner = Planner::factory()->create(); - $this->createAction = new CreateUserAction(); - $this->deleteAction = new DeleteUserAction(); + $this->createAction = new CreateUserAction; + $this->deleteAction = new DeleteUserAction; } public function test_complete_user_lifecycle_with_actions(): void @@ -33,9 +36,9 @@ public function test_complete_user_lifecycle_with_actions(): void 'name' => 'Integration Test User', 'planner_id' => $this->planner->id, ]; - + $user = $this->createAction->execute($userData); - + $this->assertInstanceOf(User::class, $user); $this->assertEquals('Integration Test User', $user->name); $this->assertEquals($this->planner->id, $user->planner_id); @@ -44,11 +47,11 @@ public function test_complete_user_lifecycle_with_actions(): void 'name' => 'Integration Test User', 'planner_id' => $this->planner->id, ]); - + // Test deletion $userId = $user->id; $result = $this->deleteAction->execute($user); - + $this->assertTrue($result); $this->assertDatabaseMissing('users', ['id' => $userId]); } @@ -60,28 +63,28 @@ public function test_creating_and_deleting_user_with_relationships(): void 'name' => 'User With Relationships', 'planner_id' => $this->planner->id, ]); - + // Create a dish and associate it with the user - $dish = \App\Models\Dish::factory()->create(['planner_id' => $this->planner->id]); + $dish = Dish::factory()->create(['planner_id' => $this->planner->id]); $user->dishes()->attach($dish->id); - + // Verify the relationship exists $this->assertEquals(1, $user->dishes()->count()); $this->assertDatabaseHas('user_dishes', [ 'user_id' => $user->id, 'dish_id' => $dish->id, ]); - + // Delete the user $userId = $user->id; $result = $this->deleteAction->execute($user); - + // Verify deletion and cascade $this->assertTrue($result); $this->assertDatabaseMissing('users', ['id' => $userId]); $this->assertDatabaseMissing('user_dishes', ['user_id' => $userId]); - + // Dish should still exist $this->assertDatabaseHas('dishes', ['id' => $dish->id]); } -} \ No newline at end of file +} diff --git a/tests/Unit/Schedule/Actions/ClearScheduleForMonthActionTest.php b/tests/Unit/Schedule/Actions/ClearScheduleForMonthActionTest.php index f3faa44..a41ef24 100644 --- a/tests/Unit/Schedule/Actions/ClearScheduleForMonthActionTest.php +++ b/tests/Unit/Schedule/Actions/ClearScheduleForMonthActionTest.php @@ -24,7 +24,7 @@ protected function setUp(): void { parent::setUp(); $this->setUpHasPlanner(); - $this->action = new ClearScheduleForMonthAction(); + $this->action = new ClearScheduleForMonthAction; } public function test_clears_scheduled_user_dishes_for_month(): void @@ -38,7 +38,7 @@ public function test_clears_scheduled_user_dishes_for_month(): void $year = 2026; $daysInMonth = Carbon::createFromDate($year, $month, 1)->daysInMonth; - (new GenerateScheduleForMonthAction())->execute($planner, $month, $year, [$user->id]); + (new GenerateScheduleForMonthAction)->execute($planner, $month, $year, [$user->id]); $this->assertEquals($daysInMonth, ScheduledUserDish::where('user_id', $user->id)->count()); @@ -60,7 +60,7 @@ public function test_only_clears_specified_users(): void $year = 2026; $daysInMonth = Carbon::createFromDate($year, $month, 1)->daysInMonth; - (new GenerateScheduleForMonthAction())->execute($planner, $month, $year, [$user1->id, $user2->id]); + (new GenerateScheduleForMonthAction)->execute($planner, $month, $year, [$user1->id, $user2->id]); $this->assertEquals($daysInMonth * 2, ScheduledUserDish::whereIn('user_id', [$user1->id, $user2->id])->count()); $this->action->execute($planner, $month, $year, [$user1->id]); @@ -80,8 +80,8 @@ public function test_does_not_affect_other_months(): void $janDays = Carbon::createFromDate($year, 1, 1)->daysInMonth; $febDays = Carbon::createFromDate($year, 2, 1)->daysInMonth; - (new GenerateScheduleForMonthAction())->execute($planner, 1, $year, [$user->id]); - (new GenerateScheduleForMonthAction())->execute($planner, 2, $year, [$user->id]); + (new GenerateScheduleForMonthAction)->execute($planner, 1, $year, [$user->id]); + (new GenerateScheduleForMonthAction)->execute($planner, 2, $year, [$user->id]); $this->assertEquals($janDays + $febDays, ScheduledUserDish::where('user_id', $user->id)->count()); diff --git a/tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php b/tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php index 7635ec8..7c55a84 100644 --- a/tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php +++ b/tests/Unit/Schedule/Actions/DraftScheduleForDateActionTest.php @@ -35,12 +35,11 @@ public function test_user_can_draft_schedule(): void $schedule = Schedule::create([ 'planner_id' => $planner->id, - 'date' => now()->addDay() + 'date' => now()->addDay(), ]); resolve(DraftScheduleForDateAction::class)->execute($schedule); - $this->assertDatabaseCount(Schedule::class, $expectedScheduleCount); $this->assertDatabaseCount(ScheduledUserDish::class, $expectedScheduleCount * User::all()->count()); } diff --git a/tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php b/tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php index e30758e..ddedb87 100644 --- a/tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php +++ b/tests/Unit/Schedule/Actions/DraftScheduleForPeriodActionTest.php @@ -14,9 +14,9 @@ class DraftScheduleForPeriodActionTest extends TestCase { + use DishesTestTrait; use HasPlanner; use RefreshDatabase; - use DishesTestTrait; protected function setUp(): void { @@ -35,11 +35,9 @@ public function test_user_can_generate_schedule(): void $this->assertDatabaseCount(Schedule::class, 0); - resolve(DraftScheduleForPeriodAction::class) ->execute($planner, CarbonPeriod::create(now()->addDay(), now()->addDays($expectedPeriodScheduleCount))); - $this->assertDatabaseCount(Schedule::class, $expectedPeriodScheduleCount); $this->assertDatabaseCount(ScheduledUserDish::class, $expectedPeriodScheduleCount * User::all()->count()); } diff --git a/tests/Unit/Schedule/Actions/GenerateScheduleForMonthActionTest.php b/tests/Unit/Schedule/Actions/GenerateScheduleForMonthActionTest.php index 16714fe..77b5fd6 100644 --- a/tests/Unit/Schedule/Actions/GenerateScheduleForMonthActionTest.php +++ b/tests/Unit/Schedule/Actions/GenerateScheduleForMonthActionTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { parent::setUp(); $this->setUpHasPlanner(); - $this->action = new GenerateScheduleForMonthAction(); + $this->action = new GenerateScheduleForMonthAction; } public function test_generates_schedule_for_entire_month(): void diff --git a/tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php b/tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php index 89e0fbf..e297016 100644 --- a/tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php +++ b/tests/Unit/Schedule/Actions/RegenerateScheduleForDateForUsersActionTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { parent::setUp(); $this->setUpHasPlanner(); - $this->action = new RegenerateScheduleForDateForUsersAction(); + $this->action = new RegenerateScheduleForDateForUsersAction; } public function test_regenerates_schedule_for_single_date(): void diff --git a/tests/Unit/Schedule/ScheduleGeneratorTest.php b/tests/Unit/Schedule/ScheduleGeneratorTest.php index db24196..fa2d65d 100644 --- a/tests/Unit/Schedule/ScheduleGeneratorTest.php +++ b/tests/Unit/Schedule/ScheduleGeneratorTest.php @@ -4,7 +4,6 @@ use App\Models\Dish; use App\Models\MinimumRecurrence; -use App\Models\Planner; use App\Models\Schedule; use App\Models\User; use App\Models\UserDish; @@ -40,7 +39,7 @@ public function test_it_fills_up_the_next_2_weeks(): void $this->assertDatabaseEmpty(Schedule::class); - (new ScheduleGenerator())->generate($planner); + (new ScheduleGenerator)->generate($planner); $schedules = Schedule::all(); $this->assertTrue($schedules->isNotEmpty()); @@ -81,9 +80,7 @@ public function test_it_takes_weekly_recurrences_into_account(): void $this->assertDatabaseEmpty(Schedule::class); - - (new ScheduleGenerator())->generate($planner); - + (new ScheduleGenerator)->generate($planner); $this->assertTrue(Schedule::all()->isNotEmpty()); @@ -127,9 +124,7 @@ public function test_it_takes_minimum_recurrences_into_account(): void $this->assertDatabaseEmpty(Schedule::class); - - (new ScheduleGenerator())->generate($planner); - + (new ScheduleGenerator)->generate($planner); $this->assertTrue(Schedule::all()->isNotEmpty()); diff --git a/tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php b/tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php index 6e6c841..6c11d28 100644 --- a/tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php +++ b/tests/Unit/Schedule/Services/ScheduleCalendarServiceTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { parent::setUp(); $this->setUpHasPlanner(); - $this->service = new ScheduleCalendarService(); + $this->service = new ScheduleCalendarService; } public function test_returns_31_calendar_days(): void diff --git a/tests/Unit/ScheduleRepositoryTest.php b/tests/Unit/ScheduleRepositoryTest.php index b0f93c5..3e151d4 100644 --- a/tests/Unit/ScheduleRepositoryTest.php +++ b/tests/Unit/ScheduleRepositoryTest.php @@ -28,7 +28,7 @@ public function test_find_or_create_finds_existing_model(): void $this->assertDatabaseCount(Schedule::class, 1); - $schedule = (new ScheduleRepository())->findOrCreate($planner, $date); + $schedule = (new ScheduleRepository)->findOrCreate($planner, $date); $this->assertDatabaseCount(Schedule::class, 1); $this->assertEquals($date, $schedule->date); @@ -41,7 +41,7 @@ public function test_find_or_create_creates_new_schedule_for_date(): void $this->assertDatabaseEmpty(Schedule::class); - $schedule = (new ScheduleRepository())->findOrCreate($planner, $date); + $schedule = (new ScheduleRepository)->findOrCreate($planner, $date); $this->assertDatabaseCount(Schedule::class, 1); $this->assertEquals($date, $schedule->date); diff --git a/tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php b/tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php index c452a01..2dd0e2a 100644 --- a/tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php +++ b/tests/Unit/ScheduledUserDish/Actions/DeleteScheduledUserDishForDateActionTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { parent::setUp(); $this->setUpHasPlanner(); - $this->action = new DeleteScheduledUserDishForDateAction(); + $this->action = new DeleteScheduledUserDishForDateAction; } public function test_deletes_scheduled_user_dish(): void diff --git a/tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php b/tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php index 2a592c6..ab45dc1 100644 --- a/tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php +++ b/tests/Unit/ScheduledUserDish/Actions/SkipScheduledUserDishForDateActionTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { parent::setUp(); $this->setUpHasPlanner(); - $this->action = new SkipScheduledUserDishForDateAction(); + $this->action = new SkipScheduledUserDishForDateAction; } public function test_skips_scheduled_user_dish(): void diff --git a/tests/Unit/UpdateScheduledUserDishActionTest.php b/tests/Unit/UpdateScheduledUserDishActionTest.php index b87f351..0d41f72 100644 --- a/tests/Unit/UpdateScheduledUserDishActionTest.php +++ b/tests/Unit/UpdateScheduledUserDishActionTest.php @@ -27,7 +27,7 @@ public function test_dish_of_scheduled_user_dish_can_be_updated(): void $schedule = Schedule::factory()->planner($planner)->create(); $scheduledUserDish = ScheduledUserDish::factory()->schedule($schedule)->userDish($userDish)->create(); - (new UpdateScheduledUserDishAction())->execute($scheduledUserDish, $otherUserDish); + (new UpdateScheduledUserDishAction)->execute($scheduledUserDish, $otherUserDish); $scheduledUserDish->refresh(); $this->assertEquals($otherUserDish->id, $scheduledUserDish->user_dish_id); diff --git a/tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php b/tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php index 3e904e0..18b0011 100644 --- a/tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php +++ b/tests/Unit/UserDish/Repositories/UserDishRepositoryTest.php @@ -45,12 +45,10 @@ public function test_find_interfering_dishes(): void ScheduledUserDish::factory()->userDish($userDishRecurring)->schedule($schedule)->create(); $this->actingAs($planner); - /** UserDishRepository $userDishRepository */ $userDishRepository = resolve(UserDishRepository::class); $userDishes = $userDishRepository->findInterferingUserDishes($user, $date); - $this->assertCount(1, $userDishes); $this->assertEquals($userDishRecurring->id, $userDishes->first()->id); } @@ -75,12 +73,10 @@ public function test_find_candidates_for_date(): void ScheduledUserDish::factory()->userDish($userDishRecurring)->schedule($schedule)->create(); $this->actingAs($planner); - /** UserDishRepository $userDishRepository */ $userDishRepository = resolve(UserDishRepository::class); $userDishes = $userDishRepository->findCandidatesForDate($user, $date); - $this->assertEquals($userDishes->pluck('id')->toArray(), [$userDishPlain->id]); } }