Files
Jobhero_back/app/Support/FormBuilder.php
CarlosTorres 5e3b203f84 Fix: Correcciones panel admin y API frontend
## Panel de Administración

### FormBuilder personalizado (Laravel 11)
- Creado app/Support/FormBuilder.php como reemplazo de laravelcollective/html
- Creado app/Support/Facades/Form.php para el facade
- Registrado en AppServiceProvider y config/app.php
- Soporta: text, email, password, file, textarea, select, checkbox, radio, etc.
- Manejo de valores null en todos los parámetros

### Configuración de sesión
- Cambiado same_site de "none" a "lax" para compatibilidad HTTP
- Corrige error 419 Page Expired en login

### Status CRUD
- Agregado campo en_name al formulario (español/inglés)
- Actualizado StatusController create/update para manejar en_name

### Dependencias
- Instalado spatie/laravel-google-cloud-storage para driver GCS

## API Frontend

### Validaciones de perfil de proveedor
Agregadas validaciones en endpoints que requieren perfil de proveedor:

- SupplierController::getpostulation - Retorna error 400 si no hay perfil
- SupplierController::getcontractedpostulation - Retorna error 400 si no hay perfil
- PostulationController::postulate - Retorna error 400 si no hay perfil
- PostulationController::getfinishedpostulations - Retorna error 400 si no hay perfil
- ContractController::startcontract - Retorna error 400 si no hay perfil

### Null safety en contratos
- ContractController::getcurrentcontracts - Manejo seguro de supplier/category null
- ContractController::getfinishedcontracts - Manejo seguro de supplier/category/status null

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 23:16:34 +00:00

266 lines
7.7 KiB
PHP

<?php
namespace App\Support;
use Illuminate\Support\HtmlString;
class FormBuilder
{
protected $model;
public function model($model, $options = [])
{
$this->model = $model;
return $this->open($options ?? []);
}
public function open($options = [])
{
$options = $options ?? [];
$method = strtoupper($options['method'] ?? 'POST');
$action = $options['url'] ?? ($options['action'] ?? '');
$files = isset($options['files']) && $options['files'] ? ' enctype="multipart/form-data"' : '';
$class = isset($options['class']) ? ' class="' . e($options['class']) . '"' : '';
$id = isset($options['id']) ? ' id="' . e($options['id']) . '"' : '';
$html = '<form method="' . ($method === 'GET' ? 'GET' : 'POST') . '" action="' . e($action) . '"' . $files . $class . $id . '>';
$html .= csrf_field();
if (!in_array($method, ['GET', 'POST'])) {
$html .= method_field($method);
}
return new HtmlString($html);
}
public function close()
{
$this->model = null;
return new HtmlString('</form>');
}
public function token()
{
return csrf_field();
}
public function label($name, $value = null, $options = [], $escapeHtml = true)
{
$options = $options ?? [];
$value = $value ?? ucfirst(str_replace('_', ' ', $name));
$for = ' for="' . e($name) . '"';
$attributes = $this->attributes($options);
return new HtmlString('<label' . $for . $attributes . '>' . ($escapeHtml ? e($value) : $value) . '</label>');
}
public function text($name, $value = null, $options = [])
{
return $this->input('text', $name, $value, $options ?? []);
}
public function email($name, $value = null, $options = [])
{
return $this->input('email', $name, $value, $options ?? []);
}
public function password($name, $options = [])
{
return $this->input('password', $name, null, $options ?? []);
}
public function hidden($name, $value = null, $options = [])
{
return $this->input('hidden', $name, $value, $options ?? []);
}
public function number($name, $value = null, $options = [])
{
return $this->input('number', $name, $value, $options ?? []);
}
public function file($name, $options = [])
{
return $this->input('file', $name, null, $options ?? []);
}
public function textarea($name, $value = null, $options = [])
{
$options = $options ?? [];
$value = $this->getValueAttribute($name, $value);
$attributes = $this->attributes(array_merge(['name' => $name, 'id' => $name], $options));
return new HtmlString('<textarea' . $attributes . '>' . e($value ?? '') . '</textarea>');
}
public function select($name, $list = [], $selected = null, $options = [], $optionsAttributes = [], $optgroupsAttributes = [])
{
$options = $options ?? [];
$list = $list ?? [];
$selected = $this->getValueAttribute($name, $selected);
$attributes = $this->attributes(array_merge(['name' => $name, 'id' => $name], $options));
$html = '<select' . $attributes . '>';
foreach ($list as $key => $value) {
if (is_array($value)) {
$html .= '<optgroup label="' . e($key) . '">';
foreach ($value as $optKey => $optValue) {
$html .= $this->option($optKey, $optValue, $selected);
}
$html .= '</optgroup>';
} else {
$html .= $this->option($key, $value, $selected);
}
}
$html .= '</select>';
return new HtmlString($html);
}
protected function option($key, $value, $selected)
{
$isSelected = $this->isSelected($key, $selected) ? ' selected' : '';
return '<option value="' . e($key) . '"' . $isSelected . '>' . e($value) . '</option>';
}
protected function isSelected($key, $selected)
{
if (is_array($selected)) {
return in_array($key, $selected);
}
return (string) $key === (string) $selected;
}
public function checkbox($name, $value = 1, $checked = null, $options = [])
{
$options = $options ?? [];
$checked = $this->getCheckedState($name, $value, $checked) ? ' checked' : '';
$attributes = $this->attributes(array_merge([
'name' => $name,
'id' => $options['id'] ?? $name,
'value' => $value,
'type' => 'checkbox'
], $options));
return new HtmlString('<input' . $attributes . $checked . '>');
}
public function radio($name, $value = null, $checked = null, $options = [])
{
$options = $options ?? [];
$checked = $this->getCheckedState($name, $value, $checked) ? ' checked' : '';
$attributes = $this->attributes(array_merge([
'name' => $name,
'id' => $options['id'] ?? $name . '_' . $value,
'value' => $value,
'type' => 'radio'
], $options));
return new HtmlString('<input' . $attributes . $checked . '>');
}
public function submit($value = null, $options = [])
{
return $this->input('submit', null, $value, $options ?? []);
}
public function button($value = null, $options = [])
{
$options = $options ?? [];
$attributes = $this->attributes(array_merge(['type' => 'button'], $options));
return new HtmlString('<button' . $attributes . '>' . e($value ?? '') . '</button>');
}
public function input($type, $name, $value = null, $options = [])
{
$options = $options ?? [];
if ($type !== 'password' && $type !== 'file') {
$value = $this->getValueAttribute($name, $value);
}
$attributes = $this->attributes(array_merge([
'type' => $type,
'name' => $name,
'id' => $options['id'] ?? $name,
'value' => $value
], $options));
return new HtmlString('<input' . $attributes . '>');
}
public function date($name, $value = null, $options = [])
{
return $this->input('date', $name, $value, $options ?? []);
}
public function time($name, $value = null, $options = [])
{
return $this->input('time', $name, $value, $options ?? []);
}
public function datetime($name, $value = null, $options = [])
{
return $this->input('datetime-local', $name, $value, $options ?? []);
}
protected function getValueAttribute($name, $value = null)
{
if (is_null($name)) {
return $value;
}
$old = old($name);
if (!is_null($old)) {
return $old;
}
if (!is_null($value)) {
return $value;
}
if ($this->model && isset($this->model->{$name})) {
return $this->model->{$name};
}
return null;
}
protected function getCheckedState($name, $value, $checked)
{
$old = old($name);
if (!is_null($old)) {
return $old == $value;
}
if (!is_null($checked)) {
return $checked;
}
if ($this->model && isset($this->model->{$name})) {
return $this->model->{$name} == $value;
}
return false;
}
protected function attributes($attributes)
{
$attributes = $attributes ?? [];
$html = '';
foreach ($attributes as $key => $value) {
if (is_null($value)) {
continue;
}
if (is_numeric($key)) {
$html .= ' ' . $value;
} else {
$html .= ' ' . $key . '="' . e($value) . '"';
}
}
return $html;
}
}