PHP code example of xentral / laravel-api

1. Go to this page and download the library: Download xentral/laravel-api library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

xentral / laravel-api example snippets




use Illuminate\Http\Resources\Json\JsonResource;
use OpenApi\Attributes as OA;
#[OA\Schema(
    schema: 'SalesOrder',
    esOrderStatus::class),
        new OA\Property(property: 'customer', anyOf: [
            new OA\Schema(ref: CustomerResource::class),
            new OA\Schema(properties: [new OA\Property(property: 'id', type: 'integer')], type: 'object'),
        ]
        ),
        new OA\Property(property: 'positions', type: 'array', items: new OA\Items(ref: SalesOrderPositionResource::class), nullable: true),
        new OA\Property(property: 'created_at', type: 'datetime'),
        new OA\Property(property: 'updated_at', type: 'datetime'),
    ],
    type: 'object',
    additionalProperties: false,
)]
class SalesOrderResource extends JsonResource
{
    /** @var SalesOrder */
    public $resource;

    public function toArray($request): array
    {
        return [
            'id' => $this->resource->id,
            'status' => $this->resource->status,
            'customer' => $this->whenLoaded('customer', fn () => new CustomerResource($this->resource->customer), ['id' => $this->resource->customer_id]),
            'positions' => $this->whenLoaded('positions', fn () => SalesOrderPositionResource::collection($this->resource->positions)),
            'created_at' => $this->resource->created_at->format(DATE_ATOM),
            'updated_at' => $this->resource->updated_at->format(DATE_ATOM),
        ];
    }
}



use Illuminate\Http\Resources\Json\ResourceCollection;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\AllowedSort;
use Xentral\LaravelApi\Query\Filters\QueryFilter;
use Xentral\LaravelApi\OpenApi\Filters\DateFilter;
use Xentral\LaravelApi\OpenApi\Filters\IdFilter;
use Xentral\LaravelApi\OpenApi\Filters\StringFilter;
use Xentral\LaravelApi\OpenApi\QuerySort;
use Xentral\LaravelApi\OpenApi\PaginationType;
use Xentral\LaravelApi\Query\QueryBuilder;

// Simple endpoint with single pagination type
#[ListEndpoint(
        path: '/api/v1/sales-orders',
        resource: SalesOrderResource::class,
        description: 'Paginated list of sales orders',
        'documentDate', 'datum'),
                new AllowedFilter('positions.count', new RelationCountFilter(),'positions'),
                // ...
            ])
            ->allowedSorts([
                AllowedSort::field('created_at'),
                AllowedSort::field('updated_at'),
            ])
            ->allowedIncludes([
                'customer',
                'positions',
            ])
            ->apiPaginate(PaginationType::SIMPLE);

        return SalesOrderResource::collection($salesOrders);
    }

// Advanced endpoint with multiple pagination types
#[ListEndpoint(
        path: '/api/v1/sales-orders-advanced',
        resource: SalesOrderResource::class,
        description: 'Advanced paginated list with multiple pagination options',
        

#[ListEndpoint(
    path: '/api/v1/sales-orders',
    resource: SalesOrderResource::class,
    description: 'Paginated list of sales orders',
    

QueryBuilder::for(SalesOrder::class)
    ->allowOrFilterGroups(except: ['isDeleted'])
    ->allowedFilters([...]);

new FilterParameter([...], supportsOrGroups: true)

new FilterParameter([...], supportsOrGroups: true, groupSchemaName: 'SalesOrderFilter')

use Illuminate\Database\Eloquent\Builder;
use Xentral\LaravelApi\Query\Filters\IdFilterTarget;
use Xentral\LaravelApi\Query\Filters\QueryFilter;

QueryFilter::identifierCallback(
    'categories.id',
    fn (Builder $query, array $ids) => $query->whereHas(
        'categories',
        fn (Builder $categories) => $categories->whereIn('product_category.id', $ids),
    ),
    IdFilterTarget::Relation,
),

use Xentral\LaravelApi\Query\Filters\FilterValue;

FilterValue::toBool($value['value'], $filterName);  // true|1|'1'|'true' / false|0|'0'|'false'
FilterValue::toIds($value['value'], $filterName);   // non-empty list<int>

// Snake case (default): current_page, per_page, last_page
'pagination_response' => [
    'casing' => 'snake',
],

// Camel case: currentPage, perPage, lastPage  
'pagination_response' => [
    'casing' => 'camel',
],



use Xentral\LaravelApi\Query\QueryBuilder;
#[GetEndpoint(
        path: '/api/v1/sales-orders/{id}',
        resource: SalesOrderResource::class,
        description: 'View a single sales order',
        tags: ['SalesOrder'],
          ->findOrFail($id);

        return new SalesOrderResource($salesOrder);
    }



use Illuminate\Foundation\Http\FormRequest;
use OpenApi\Attributes as OA;

#[OA\Schema(
    schema: 'CreateSalesOrderRequest',
    id', type: 'integer')]),
        new OA\Property(property: 'customer', type: 'object', ce'],
            properties: [
                new OA\Property(property: 'sku', type: 'string'),
                new OA\Property(property: 'quantity', type: 'integer'),
                new OA\Property(property: 'price', ref: '#/components/schemas/Money'),
            ])),
    ],
    type: 'object',
)]
class CreateSalesOrderRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'project.id' => ['



#[PostEndpoint(
        path: '/api/v1/sales-orders',
        request: CreateSalesOrderRequest::class,
        resource: SalesOrderResource::class,
        description: 'Create a new sales order',
        tags: ['SalesOrder'],
        successStatus: '201',
    )]
    public function create(CreateSalesOrderRequest $request): SalesOrderResource
    {
        $salesOrder = SalesOrder::create([
            // ...
        ]);

        return new SalesOrderResource($salesOrder);
    }





#[PatchEndpoint(
        path: '/api/v1/sales-orders/{id}',
        request: UpdateSalesOrderRequest::class,
        resource: SalesOrderResource::class,
        description: 'Update an existing sales order',
        tags: ['SalesOrder'],
    )]
    public function update(UpdateSalesOrderRequest $request, int $id): SalesOrderResource
    {
        $salesOrder = SalesOrder::with('positions')->findOrFail($id);

        // Handle update logic here, e.g. updating positions, customer, etc.

        return new SalesOrderResource($salesOrder);
    }



use Illuminate\Http\Response;
use Illuminate\Validation\ValidationException;

    #[DeleteEndpoint(
        path: '/api/v1/sales-orders/{id}',
        description: 'Delete a sales order',
        tags: ['SalesOrder'],
        validates: ['status' => 'Only pending sales orders can be deleted.'],
    )]
    public function delete(int $id): Response
    {
        $salesOrder = SalesOrder::findOrFail($id);

        if ($salesOrder->status !== SalesOrderStatus::PENDING) {
            throw ValidationException::withMessages([
                'status' => 'Only pending sales orders can be deleted. Current status: '.$salesOrder->status->value,
            ]);
        }

        $salesOrder->positions()->delete();
        $salesOrder->delete();

        return response()->noContent();
    }

return [
    'docs' => [
        'enabled' => env('APP_ENV') !== 'production',
        'prefix' => 'api-docs',
        'middleware' => ['web', 'auth'],
        'client' => env('OPENAPI_CLIENT', 'swagger'), // 'swagger' or 'scalar'
    ],
    'schemas' => [
        'default' => [
            'client' => null, // Uses global client setting if null, otherwise: 'swagger' or 'scalar'
            'oas_version' => '3.1.0',
            'ruleset' => null,
            'folders' => [base_path('app')],
            'output' => base_path('openapi.yml'),
            'deprecation_filter' => [
                'enabled' => true,
                'months_before_removal' => 6,
            ],
            'feature_flags' => [
                'description_prefix' => "This endpoint is only available if the feature flag `{flag}` is enabled.\n\n",
            ],
            'validation_response' => [
                'status_code' => 422,
                'content_type' => 'application/json',
                'max_errors' => 3,
                'content' => [
                    'message' => 'The given data was invalid.',
                    'errors' => '{{errors}}',
                ],
            ],
            'pagination_response' => [
                'casing' => 'snake', // 'snake' or 'camel'
            ],
            'validation_commands' => [],
            'validation_status_code' => 422,
            'name' => 'My API',
            'version' => '1.0.0',
            'description' => 'Developer API',
            'contact' => [
                'name' => 'API Support',
                'url' => env('APP_URL', 'https://example.com'),
                'email' => env('MAIL_FROM_ADDRESS', '[email protected]'),
            ],
            'servers' => [
                [
                    'url' => env('APP_URL', 'https://example.com'),
                    'description' => 'Your API environment',
                ],
            ],
        ],
    ],
];

'schemas' => [
    'v1' => [
        'folders' => [base_path('app/Http/Controllers/Api/V1')],
        'output' => base_path('openapi-v1.yml'),
        // other settings...
    ],
    'v2' => [
        'folders' => [base_path('app/Http/Controllers/Api/V2')],
        'output' => base_path('openapi-v2.yml'),
        // other settings...
    ],
],

'docs' => [
    'enabled' => env('APP_ENV') !== 'production', // Enable or disable the web interface
    'prefix' => 'api-docs', // URL prefix for the web interface
    'middleware' => ['web', 'auth'], // Middleware applied to the web interface routes
    'client' => env('OPENAPI_CLIENT', 'swagger'), // API documentation client: 'swagger' or 'scalar'
],

// config/openapi.php
'docs' => [
    'client' => 'scalar', // Global default for all schemas
],

// config/openapi.php
'schemas' => [
    'default' => [
        'client' => 'scalar', // Override for this specific schema
        // other settings...
    ],
    'v2' => [
        'client' => 'swagger', // Different client for v2 API
        // other settings...
    ],
],



namespace App\OpenApi\Filters;

use Xentral\LaravelApi\Query\Filters\FilterType;use Xentral\LaravelApi\OpenApi\Filters\FilterProperty;use Xentral\LaravelApi\OpenApi\Filters\FilterSpecCollection;

#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class UserFilters implements FilterSpecCollection
{
    public function getFilterSpecification(): array
    {
        return [
            new FilterProperty(
                name: 'name',
                description: 'Filter users by name',
                type: 'string',
                filterType: FilterType::PARTIAL
            ),
            new FilterProperty(
                name: 'email',
                description: 'Filter users by email',
                type: 'string',
                filterType: FilterType::EXACT
            ),
            new FilterProperty(
                name: 'created_at',
                description: 'Filter users by creation date',
                type: 'string',
                filterType: FilterType::OPERATOR,
                operators: ['eq', 'gt', 'lt', 'gte', 'lte']
            ),
        ];
    }
}

#[ListEndpoint(
    path: '/api/v1/users',
    resource: UserResource::class,
    description: 'Paginated list of users',
    parameters: [
        new UserFilters(),
        new QuerySort(['created_at', 'updated_at']),
    ],
    paginationType: PaginationType::SIMPLE,
    tags: ['User'],
)]
public function index(): ResourceCollection
{
    $users = QueryBuilder::for(User::class)
        ->defaultSort('-created_at')
        ->allowedFilters([
            QueryFilter::string('name'),
            QueryFilter::string('email'),
            QueryFilter::date('created_at'),
        ])
        ->allowedSorts([
            AllowedSort::field('created_at'),
            AllowedSort::field('updated_at'),
        ])
        ->apiPaginate(PaginationType::SIMPLE);

    return UserResource::collection($users);
}
yaml
-
  name: include
  in: query
  description: '`files` ray
    items:
      type: string
      enum:
        - customer
        - positions
        - files
  x-
bash
/api/v1/sales-orders?page=2&per_page=50
bash
/api/v1/sales-orders?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0&per_page=50
bash
php artisan openapi:generate
bash
php artisan vendor:publish --provider="Xentral\LaravelApi\ApiServiceProvider"
bash
php artisan openapi:generate v1