array request not render and not examplae
haidv1992 opened this issue · 2 comments
haidv1992 commented
Scribe version
4.35.0
PHP version
8.2
Framework
Laravel
Framework version
v10.48.10
Scribe config
php artisan scribe:config:diff
laravel.middleware.0 => ""
try_it_out.use_csrf => true
auth.enabled => true
auth.default => true
What happened?
File request
namespace Modules\Plan\app\Http\Requests;
use App\Models\PosUpdate;
use App\Pos;
use App\Support\Enum\ActionCode;
use Carbon\Carbon;
use Illuminate\Foundation\Http\FormRequest;
use Modules\Plan\app\Models\Plan;
use Modules\Plan\app\Models\PlanResult;
use Modules\Plan\app\Services\PlanConfigurationService;
class CheckinRequest extends FormRequest
{
protected $bodyParams = array();
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
$configService = app(PlanConfigurationService::class);
$config = $configService->getCheckinConfiguration();
$posChecklists = $configService->getChecklistsConfiguration();
$rules = [
'plan_id' => 'sometimes|nullable|exists:plans,id',
'posCode' => 'required|exists:pos,posCode',
];
if (!empty($posChecklists)) {
$checklistCount = count($posChecklists);
$rules['checklist'] = ['required', 'array', 'min:'.$checklistCount, 'max:'.$checklistCount];
$checklistRules = [
'*.id' => 'required|integer|exists:pos_checklists,id',
'*.status' => 'required|boolean',
'*.note' => 'nullable|string',
'*.photo' => 'nullable|file|mimetypes:image/jpeg,image/jpg,image/png,image/webp|max:500',
];
$rules['checklist.*'] = $checklistRules;
foreach ($posChecklists as $item) {
$this->bodyParams['checklist'][] = [
'id' => [
'description' => 'ID of the checklist item',
'example' => $item->id
],
'status' => [
'description' => "Status of the checklist item {$item->name}",
'example' => true
],
'note' => [
'description' => 'Note for the checklist item',
'example' => 'This is a sample note'
],
'photo' => [
'description' => 'Optional photo for the checklist item',
'example' => new \Illuminate\Http\UploadedFile(public_path('assets/media/demo/checkin/img-1.png'), 'sample.jpg')
],
];
}
}
foreach ($config as $item) {
$this->addConfigRules($rules, $item);
}
return $rules;
}
protected function prepareForValidation()
{
$checklistData = $this->input('checklist', []);
foreach ($checklistData as $id => &$data) {
if (isset($data['status'])) {
$data['status'] = filter_var($data['status'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
}
$this->merge([
'checklist' => $checklistData,
]);
}
public function withValidator($validator)
{
$validator->after(function ($validator) {
if (!$validator->errors()->isEmpty()) {
return $validator;
}
$this->handleChecklistsValidation($validator);
$this->handlePostValidation($validator);
});
}
protected function handleChecklistsValidation($validator){
$configService = app(PlanConfigurationService::class);
$requiredChecklistIds = $configService->getChecklistsConfiguration()->pluck('id')->sort()->values()->all();
$submittedChecklistIds = collect($this->input('checklist', []))
->pluck('id')
->sort()
->values()
->all();
if ($requiredChecklistIds !== $submittedChecklistIds) {
$validator->errors()->add('checklist', 'Tất cả các mục trong danh sách kiểm tra phải được bao gồm và khớp với ID được yêu cầu.');
}
}
protected function handlePostValidation($validator)
{
$mergeData = [];
$planOrPos = $this->planOrPosExists();
$pendingUpdate = $this->checkForPendingUpdates($validator);
if ($pendingUpdate) {
$mergeData['pendingUpdate'] = $pendingUpdate;
}
if (!$this->input('plan_id')) {
$this->handleNoPlanOrPos($validator, $mergeData);
$lastAction = $mergeData['lastAction'];
} elseif (!$planOrPos) {
$validator->errors()->add('error', 'Không tìm thấy kế hoạch hoặc điểm bán phù hợp.');
return;
} else {
$mergeData['plan'] = $planOrPos;
$mergeData['pos'] = $planOrPos->pos()->where('posCode', $this->posCode)->first();
$lastAction = $mergeData['pos']->visits()->latest()->first();
}
if ($lastAction && $lastAction->action_code == ActionCode::ACTION_CHECK_IN) {
$validator->errors()->add('action_code', 'Check-out is required before check-in.');
}
$this->merge($mergeData);
}
protected function handleNoPlanOrPos($validator, &$mergeData)
{
$pos = Pos::where('posCode', $this->input('posCode'))->first();
if (!$pos) {
$validator->errors()->add('posCode', 'No valid POS found with provided POS Code.');
return; // Exit early if no valid POS is found to prevent further processing
}
$lastAction = $pos->visits()->latest()->first();
$mergeData['pos'] = $pos;
$mergeData['lastAction'] = $lastAction; // Store last action to use in post validation checks
}
private function planOrPosExists()
{
$posCode = $this->input('posCode');
return Plan::with('pos')
->where('month', Carbon::now()->format('Y-m'))
->where('status', Plan::STATUS_PLAN_APPROVED)
->whereHas('pos', function ($query) use ($posCode) {
$query->where('posCode', $posCode);
})
->find($this->input('plan_id'));
}
private function checkForPendingUpdates($validator)
{
$posCode = $this->input('posCode');
$pendingUpdate = PosUpdate::where('pos_id', $posCode)
->where('status', PosUpdate::STATUS_PENDING)
->first();
if ($pendingUpdate) {
$existingCheckin = PlanResult::where('posCode', $posCode)
->where('pos_update_id', $pendingUpdate->id)
->first();
if ($existingCheckin) {
$validator->errors()->add('pos_update', 'Check-in không được phép do tồn tại một đề xuất đang chờ duyệt.');
}
}
return $pendingUpdate;
}
protected function addConfigRules(&$rules, $item)
{
switch ($item['type']) {
case 'file':
$this->handleFileRules($rules, $item);
break;
case 'coordinates':
$rules['lat'] = 'required|numeric';
$rules['lon'] = 'required|numeric';
break;
}
}
protected function handleFileRules(&$rules, $item)
{
$baseKey = $item['key'];
$rules[$baseKey] = [
'required',
'array',
'max:' . $item['max_photos'],
];
$rules[$baseKey . '.*'] = [
'file',
'mimetypes:' . $item['rules']['mimetypes'],
'max:' . $item['rules']['max'],
'dimensions:max_width=' . $item['rules']['max_width'],
];
$this->bodyParams[$baseKey] = [
'description' => "{$item['name']} - {$item['description']}",
"required" => true,
'example' => new \Illuminate\Http\UploadedFile(public_path('assets/media/demo/checkin/img-1.png'), 'sample.jpg')
];
}
public function bodyParameters()
{
return array_merge([
'plan_id' => [
'description' => 'ID kế hoạch',
'example' => 1
],
'posCode' => [
'description' => 'Mã điểm bán',
'example' => 124000010436
],
// 'checklist' => [
// 'description' => 'Điểm bán sẵn sàng để bán hàng?. [Get list](/docs#pos-GETapi-v1-pos-pos-readiness-checklists)',
// ],
], $this->bodyParams);
}
}
php artisan scribe:generate
Docs
- I've checked the docs, the troubleshooting guide, and existing issues, but I didn't find a solution
AryaSvitkona commented
We are facing the same "issue", since we won't use a data
wrapper in our request like:
{
"data":
[
{
"name": "foo",
"type": "bar"
},
]
}
To make it short:
In the provided example you are trying to generate the documentation by using FormRequest, in where you check properties of an object which is provided as array. Right?
$checklistRules = [
'*.id' => 'required|integer|exists:pos_checklists,id',
'*.status' => 'required|boolean',
'*.note' => 'nullable|string',
'*.photo' => 'nullable|file|mimetypes:image/jpeg,image/jpg,image/png,image/webp|max:500',
];
Can scribe handle this?
shalvah commented
What exactly is the issue? (Sorry for the late reply.) The image you uploaded gives me a 404.