File manager - Edit - /var/www/html/portal/app/Http/Requests/Accounts/Cronogramas/CronogramasRequest.php
Back
<?php namespace App\Http\Requests\Accounts\Cronogramas; use App\Enums\Accounts\Cronogramas\CronogramaActivityStatus; use App\Enums\Accounts\Cronogramas\CronogramaProjectStatus; use App\Enums\Accounts\Cronogramas\CronogramaResponsibleType; use App\Models\Empresa; use App\Models\Structure; use App\Models\UnidadeOrganizacional; use App\Models\User; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Http\UploadedFile; use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\File; /** * Validação centralizada do módulo Cronogramas. */ class CronogramasRequest extends FormRequest { public function authorize(): bool { return auth()->check(); } /** * @return array<string, string> */ public function messages(): array { return [ 'name.required' => __('Informe o nome do projeto.'), 'name.max' => __('O nome do projeto não pode ter mais de :max caracteres.'), 'description.max' => __('A descrição não pode ter mais de :max caracteres.'), 'planned_end_date.after_or_equal' => __('A data fim prevista deve ser igual ou posterior à data de início.'), 'scope_structures.*.exists' => __('Um ou mais órgãos selecionados são inválidos.'), 'scope_unidades.*.exists' => __('Uma ou mais unidades selecionadas são inválidas.'), 'scope_empresas.*.exists' => __('Uma ou mais empresas selecionadas são inválidas.'), 'title.required' => __('Informe o título da atividade.'), 'title.max' => __('O título da atividade não pode ter mais de :max caracteres.'), 'planned_end_date.after_or_equal' => __('A data fim prevista da atividade deve ser igual ou posterior à data de início.'), 'notes.max' => __('As observações não podem ter mais de :max caracteres.'), 'order.required' => __('Informe a ordem das atividades.'), 'order.min' => __('Informe ao menos uma atividade para reordenar.'), 'activity_ids.required' => __('Selecione ao menos uma atividade arquivada.'), 'activity_ids.min' => __('Selecione ao menos uma atividade arquivada.'), 'project_ids.required' => __('Selecione ao menos um projeto arquivado.'), 'project_ids.min' => __('Selecione ao menos um projeto arquivado.'), 'content.required' => __('Informe o conteúdo do comentário.'), 'content.max' => __('O comentário não pode ter mais de :max caracteres.'), 'attachments.required' => __('Selecione ao menos um arquivo.'), 'attachments.min' => __('Selecione ao menos um arquivo.'), 'attachments.*.max' => __('Um ou mais arquivos excedem o tamanho máximo permitido.'), ]; } protected function prepareForValidation(): void { $name = (string) $this->route()?->getName(); // Garante que remover todas as predecessoras na criação/edição limpe o vínculo // (multiselect vazio não é enviado pelo navegador). Não se aplica ao inline. if (in_array($name, [ 'admin.cronogramas.atividades.store', 'admin.cronogramas.atividades.update', ], true) && ! $this->has('predecessor_ids')) { $this->merge(['predecessor_ids' => []]); } if (in_array($name, [ 'admin.cronogramas.atividades.store', 'admin.cronogramas.atividades.update', ], true)) { // Normaliza responsáveis: garante array e descarta itens incompletos, // permitindo que o envio vazio limpe todos os vínculos. $responsibles = $this->input('responsibles'); $clean = []; foreach ((is_array($responsibles) ? $responsibles : []) as $item) { if (! is_array($item)) { continue; } $type = $item['type'] ?? null; $id = $item['id'] ?? null; if (! empty($type) && ! empty($id)) { $clean[] = ['type' => (string) $type, 'id' => (string) $id]; } } $this->merge(['responsibles' => $clean]); } if (in_array($name, [ 'admin.cronogramas.projetos.store', 'admin.cronogramas.projetos.update', ], true)) { foreach (['scope_structures', 'scope_unidades', 'scope_empresas'] as $field) { if (! $this->has($field)) { $this->merge([$field => []]); } } } if ($name !== 'admin.cronogramas.atividades.attachments') { return; } $raw = $this->file('attachments'); if ($raw === null) { $this->merge(['attachments' => []]); return; } $files = is_array($raw) ? $raw : [$raw]; $files = array_values(array_filter($files, static function ($f): bool { return $f instanceof UploadedFile && $f->isValid(); })); $this->merge(['attachments' => $files]); } /** * @return array<string, mixed> */ public function rules(): array { $name = (string) $this->route()->getName(); return match ($name) { 'admin.cronogramas.projetos.store' => self::rulesStoreProject(), 'admin.cronogramas.projetos.update' => self::rulesUpdateProject(), 'admin.cronogramas.atividades.store', 'admin.cronogramas.atividades.update', 'admin.cronogramas.atividades.inline' => self::rulesActivity(), 'admin.cronogramas.atividades.reorder' => self::rulesReorder(), 'admin.cronogramas.atividades.arquivadas.destroy' => self::rulesBulkDestroyArchived(), 'admin.cronogramas.projetos.arquivados.destroy' => self::rulesBulkDestroyArchivedProjects(), 'admin.cronogramas.comentarios.store' => self::rulesComment(), 'admin.cronogramas.atividades.attachments' => self::rulesAttachment(), 'admin.cronogramas.projetos.public-share' => self::rulesPublicShare(), default => [], }; } /** * @return array<string, mixed> */ public static function rulesStoreProject(): array { return [ 'name' => ['required', 'string', 'max:200'], 'description' => ['nullable', 'string', 'max:10000'], 'start_date' => ['nullable', 'date'], 'planned_end_date' => ['nullable', 'date', 'after_or_equal:start_date'], 'scope_structures' => ['nullable', 'array'], 'scope_structures.*' => ['uuid', 'exists:structures,id'], 'scope_unidades' => ['nullable', 'array'], 'scope_unidades.*' => ['uuid', 'exists:unidades_organizacionais,id'], 'scope_empresas' => ['nullable', 'array'], 'scope_empresas.*' => ['uuid', 'exists:empresas,id'], ]; } /** * @return array<string, mixed> */ public static function rulesUpdateProject(): array { return self::rulesStoreProject(); } /** * @return array<string, mixed> */ public static function rulesActivity(): array { return [ 'code' => ['nullable', 'string', 'max:32'], 'title' => ['sometimes', 'required', 'string', 'max:300'], 'description' => ['nullable', 'string', 'max:10000'], 'parent_id' => ['nullable', 'uuid'], 'responsibles' => ['nullable', 'array'], 'responsibles.*.type' => ['required_with:responsibles.*.id', Rule::in(CronogramaResponsibleType::values())], 'responsibles.*.id' => ['required_with:responsibles.*.type', 'uuid'], 'status' => ['nullable', 'string', Rule::in(CronogramaActivityStatus::values())], // O progresso (%) é derivado do status (config cronogramas.status_completion_percent), // nunca informado pelo usuário. Por isso não é validado/aceito aqui. 'planned_start_date' => ['nullable', 'date'], 'planned_end_date' => ['nullable', 'date', 'after_or_equal:planned_start_date'], 'notes' => ['nullable', 'string', 'max:5000'], 'predecessor_ids' => ['nullable', 'array'], 'predecessor_ids.*' => ['uuid'], ]; } /** * @return array<string, mixed> */ public static function rulesReorder(): array { return [ 'order' => ['required', 'array', 'min:1'], 'order.*' => ['uuid'], ]; } /** * @return array<string, mixed> */ public static function rulesBulkDestroyArchived(): array { return [ 'activity_ids' => ['required', 'array', 'min:1'], 'activity_ids.*' => ['uuid'], ]; } /** * @return array<string, mixed> */ public static function rulesBulkDestroyArchivedProjects(): array { return [ 'project_ids' => ['required', 'array', 'min:1'], 'project_ids.*' => ['uuid'], ]; } /** * @return array<string, mixed> */ public static function rulesComment(): array { return [ 'content' => ['required', 'string', 'max:5000'], ]; } /** * @return array<string, mixed> */ public static function rulesAttachment(): array { $ext = config('cronogramas.upload.allowed_extensions', []); return [ 'attachments' => ['required', 'array', 'min:1'], 'attachments.*' => [ File::types($ext)->max((int) config('cronogramas.upload.max_file_bytes', 52428800) / 1024), ], ]; } /** * @return array<string, mixed> */ public static function rulesPublicShare(): array { return [ 'enabled' => ['required', 'boolean'], ]; } public function withValidator($validator): void { $validator->after(function ($validator): void { $name = (string) $this->route()?->getName(); if (in_array($name, [ 'admin.cronogramas.projetos.store', 'admin.cronogramas.projetos.update', ], true)) { $scopeCount = count((array) $this->input('scope_structures', [])) + count((array) $this->input('scope_unidades', [])) + count((array) $this->input('scope_empresas', [])); if ($scopeCount < 1) { $validator->errors()->add( 'scope_structures', __('Selecione ao menos um escopo organizacional autorizado.'), ); } } $responsibles = $this->input('responsibles'); if (! is_array($responsibles)) { return; } foreach ($responsibles as $index => $item) { $id = is_array($item) ? ($item['id'] ?? null) : null; $type = is_array($item) ? ($item['type'] ?? null) : null; if (empty($id) || empty($type)) { continue; } $resolved = CronogramaResponsibleType::tryFrom((string) $type); if ($resolved === null) { continue; } $exists = match ($resolved) { CronogramaResponsibleType::Empresa => Empresa::query()->whereKey($id)->exists(), CronogramaResponsibleType::Structure => Structure::query()->whereKey($id)->exists(), CronogramaResponsibleType::Unidade => UnidadeOrganizacional::query()->whereKey($id)->exists(), CronogramaResponsibleType::User => User::query()->whereKey($id)->exists(), }; if (! $exists) { $validator->errors()->add( "responsibles.$index.id", __('Responsável inválido para o tipo selecionado.'), ); } } }); } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings