knuckleswtf / scribe

Generate API documentation for humans from your Laravel codebase.✍
https://scribe.knuckles.wtf/laravel/
MIT License
1.75k stars 314 forks source link

generate php docs array of object #889

Closed mbehzad-bhz closed 1 month ago

mbehzad-bhz commented 2 months ago

Scribe version

^4.37

PHP version

^8.2

Framework

Laravel

Framework version

^11.9

Scribe config

<?php

use Knuckles\Scribe\Extracting\Strategies;

return [
    'title' => 'API Documentation',
    'description' => 'Supplier Panel.',
    'base_url' => null,
    'routes' => [
        [
            'match' => [
                'prefixes' => ['api/supplier_panel/*'],
                'domains' => ['*'],
                'versions' => ['v1'],
            ],
            'include' => [],
            'exclude' => [

            ],
        ],
    ],
    'type' => 'static',
    'theme' => 'default',
    'static' => [
        'output_path' => 'public/docs/supplier',
    ],
    'laravel' => [
        'add_routes' => true,
        'docs_url' => '/docs/admin',
        'assets_directory' => null,
        'middleware' => [],
    ],
    'try_it_out' => [
        'enabled' => true,
        'base_url' => null,
        'use_csrf' => false,
        'csrf_url' => '/sanctum/csrf-cookie',
    ],
    'auth' => [
        'enabled' => true,
        'default' => false,
        'in' => 'bearer',
        'name' => 'key',
        'use_value' => env('SCRIBE_AUTH_KEY'),
        'placeholder' => '{YOUR_AUTH_KEY}',
        'extra_info' => 'You can retrieve your token by visiting your dashboard and clicking <b>Generate API token</b>.',
    ],
    'intro_text' => <<<INTRO
This documentation aims to provide all the information you need to work with our API.

<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).
You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).</aside>
INTRO,
    'example_languages' => ['bash', 'javascript'],
    'postman' => ['enabled' => true, 'overrides' => []],
    'openapi' => ['enabled' => true, 'overrides' => []],
    'groups' => ['default' => 'Endpoints', 'order' => []],
    'logo' => false,
    'last_updated' => 'Last updated: {date:F j, Y}',
    'examples' => ['faker_seed' => null, 'models_source' => ['factoryCreate', 'factoryMake', 'databaseFirst']],
    'strategies' => [
        'metadata' => [Strategies\Metadata\GetFromDocBlocks::class, Strategies\Metadata\GetFromMetadataAttributes::class],
        'urlParameters' => [Strategies\UrlParameters\GetFromLaravelAPI::class, Strategies\UrlParameters\GetFromUrlParamAttribute::class, Strategies\UrlParameters\GetFromUrlParamTag::class],
        'queryParameters' => [Strategies\QueryParameters\GetFromFormRequest::class, Strategies\QueryParameters\GetFromInlineValidator::class, Strategies\QueryParameters\GetFromQueryParamAttribute::class, Strategies\QueryParameters\GetFromQueryParamTag::class],
        'headers' => [Strategies\Headers\GetFromHeaderAttribute::class, Strategies\Headers\GetFromHeaderTag::class, ['override', ['Content-Type' => 'application/json', 'Accept' => 'application/json']]],
        'bodyParameters' => [Strategies\BodyParameters\GetFromFormRequest::class, Strategies\BodyParameters\GetFromInlineValidator::class, Strategies\BodyParameters\GetFromBodyParamAttribute::class, Strategies\BodyParameters\GetFromBodyParamTag::class],
        'responses' => [Strategies\Responses\UseResponseAttributes::class, Strategies\Responses\UseTransformerTags::class, Strategies\Responses\UseApiResourceTags::class, Strategies\Responses\UseResponseTag::class, Strategies\Responses\UseResponseFileTag::class, [Strategies\Responses\ResponseCalls::class, ['only' => ['GET *']]]],
        'responseFields' => [Strategies\ResponseFields\GetFromResponseFieldAttribute::class, Strategies\ResponseFields\GetFromResponseFieldTag::class],
    ],
//    'database_connections_to_transact' => [config('database.default')],
    'database_connections_to_transact' => [],
    'fractal' => ['serializer' => null],
    'routeMatcher' => \Knuckles\Scribe\Matching\RouteMatcher::class,
    'external' => ['html_attributes' => []],
];

What happened?

this is my php doc for endpoint that has request socialMedias with type and link in every object of array : `/**

image

and curl is : curl -X 'POST' \ 'https://example.com/api/supplier_request/sendRequest' \ -H 'accept: application/json' \ -H 'Content-Type: multipart/form-data' \ -F 'name=My Supplier' \ -F 'brandName=My Brand' \ -F 'description=Leading supplier of organic products.' \ -F 'text=We specialize in organic and eco-friendly products.' \ -F 'thumb=@3.jpeg;type=image/jpeg' \ -F 'brandLogo=@3.jpeg;type=image/jpeg' \ -F 'socialMedias=string'

it should be somthing like this : curl -X 'POST' \ 'https://example.com/api/supplier_panel/supplier_request/sendRequest' \ -H 'accept: application/json' \ -H 'Content-Type: multipart/form-data' \ -F 'name=My Supplier' \ -F 'brandName=My Brand' \ -F 'description=Leading supplier of organic products.' \ -F 'text=We specialize in organic and eco-friendly products.' \ -F 'thumb=@3.jpeg;type=image/jpeg' \ -F 'brandLogo=@3.jpeg;type=image/jpeg' \ -F 'socialMedias[0][type]=INSTAGRAM' \ -F 'socialMedias[0][link]=https://instagram.com/mybrand' \ -F 'socialMedias[1][type]=FACEBOOK' \ -F 'socialMedias[1][link]=https://facebook.com/mybrand'

would anyone be so kind as to respond to my question, please?

Docs

shalvah commented 1 month ago

Try using @bodyParam socialMedias object[] instead of @bodyParam socialMedias array.

See the examples in the docs. https://scribe.knuckles.wtf/laravel/documenting/query-body-parameters#arrays-of-objects

mbehzad-bhz commented 1 month ago

my updated code is : `/**

mbehzad-bhz commented 1 month ago

@shalvah i just change the library code and its fixed now , the below files its changed:

` @php use Knuckles\Scribe\Tools\WritingUtils as u; /* @var Knuckles\Camel\Output\OutputEndpointData $endpoint / @endphp

curl --request {{$endpoint->httpMethods[0]}} \
    {{$endpoint->httpMethods[0] == 'GET' ? '--get ' : ''}}"{!! rtrim($baseUrl, '/') !!}/{{ ltrim($endpoint->boundUri, '/') }}@if(count($endpoint->cleanQueryParameters))?{!! u::printQueryParamsAsString($endpoint->cleanQueryParameters) !!}@endif"@if(count($endpoint->headers)) \
@foreach($endpoint->headers as $header => $value)
    --header "{{$header}}: {{ addslashes($value) }}"@if(! ($loop->last) || ($loop->last && count($endpoint->bodyParameters))) \
@endif
@endforeach
@endif
@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters)))
@foreach($endpoint->cleanBodyParameters as $parameter => $value)
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue)
    --form "{!! "$key=".(is_object($actualValue) ? json_encode($actualValue) : $actualValue) !!}"@if(!($loop->parent->last) || count($endpoint->fileParameters))\
@endif
@endforeach
@endforeach
@foreach($endpoint->fileParameters as $parameter => $value)
@foreach(u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $file)
    --form "{!! "$key=@".$file->path() !!}" @if(!($loop->parent->last))\
@endif
@endforeach
@endforeach
@elseif(count($endpoint->cleanBodyParameters))
@if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded')
    --data "{!! http_build_query($endpoint->cleanBodyParameters, '', '&') !!}"
@else
    --data "{!! addslashes(json_encode($endpoint->cleanBodyParameters, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)) !!}"
@endif
@endif

`

const params = {!! u::printQueryParamsAsKeyValue($endpoint->cleanQueryParameters, "\"", ":", 4, "{}") !!}; Object.keys(params) .forEach(key => url.searchParams.append(key, params[key])); @endif

@if(!empty($endpoint->headers)) const headers = { @foreach($endpoint->headers as $header => $value) "{{$header}}": "{{$value}}", @endforeach @empty($endpoint->headers['Accept']) "Accept": "application/json", @endempty }; @endif

@if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters))) const body = new FormData(); @foreach($endpoint->cleanBodyParameters as $parameter => $value) @foreach( u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue) body.append('{!! $key !!}', '{!! is_object($actualValue) || is_array($actualValue) ? json_encode($actualValue) : addslashes($actualValue) !!}'); @endforeach @endforeach @foreach($endpoint->fileParameters as $parameter => $value) @foreach( u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $file) body.append('{!! $key !!}', document.querySelector('input[name="{!! $key !!}"]').files[0]); @endforeach @endforeach @elseif(count($endpoint->cleanBodyParameters)) @if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded') let body = "{!! http_build_query($endpoint->cleanBodyParameters, '', '&') !!}"; @else let body = {!! json_encode($endpoint->cleanBodyParameters, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) !!}; @endif @endif

fetch(url, { method: "{{$endpoint->httpMethods[0]}}", @if(count($endpoint->headers)) headers, @endif @if($endpoint->hasFiles() || (isset($endpoint->headers['Content-Type']) && $endpoint->headers['Content-Type'] == 'multipart/form-data' && count($endpoint->cleanBodyParameters))) body, @elseif(count($endpoint->cleanBodyParameters)) @if ($endpoint->headers['Content-Type'] == 'application/x-www-form-urlencoded') body, @else body: JSON.stringify(body), @endif @endif }).then(response => response.json());



`
`the changes is only about $actualValue 
@foreach( u::getParameterNamesAndValuesForFormData($parameter, $value) as $key => $actualValue)
    body.append('{!! $key !!}', '{!! is_object($actualValue) || is_array($actualValue) ? json_encode($actualValue) : addslashes($actualValue) !!}');
@endforeach`
and 
`--form "{!! "$key=".(is_object($actualValue) ? json_encode($actualValue) : $actualValue) !!}"@if(!($loop->parent->last) || count($endpoint->fileParameters))\`
shalvah commented 1 month ago

hey, to format your multiline code snippets correctly in Markdown use 3x backticks (```). So do:

``` this is multiple lines ```

and you'll get:

this is 
multiple lines

Don't do

`this is multiple lines`

because you'll get:

this is multiple lines

which makes it harder to read your code