Problem
I'm trying to use zircote/swagger-php
to generate an OpenApi file from PHP-code. For some reason I keep getting the following error:
Warning: Skipping unknown La\Product
Warning: Required @OA\PathItem() not found
Warning: Required @OA\Info() not found
Setup
I'm using a docker container to have it reproducible. My setup is as follows:
.
├── Dockerfile
├── project
│ └── myTest.php
└── swagger.php
and here is the contents of the files:
Dockerfile
FROM composer:latest
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
RUN ["composer", "require", "zircote/swagger-php"]
RUN ["composer", "require", "doctrine/annotations"]
CMD ["sh"]
Inside the container I run: ./vendor/bin/openapi project/
project/myTest.php
<?php
namespace La;
use OpenApi\Annotations as OA;
/**
* @OA\Info(title="My First API", version="0.1")
* @OA\Get(
* path="/",
* @OA\Response(response="200", description="Some description.")
* )
*/
#[SomeAttribute]
class Product {
/**
* @OA\Get(
* path="/api/data.json",
* @OA\Response(
* response="200",
* description="The data"
* )
* )
*/
public function getResource()
{
// ...
}
public $la = 12;
}
swagger.php
<?php
require("vendor/autoload.php");
$openapi = \OpenApi\Generator::scan(['project']);
header('Content-Type: application/x-yaml');
echo $openapi->toJson();
Yields same error as running a command-line command above.
Have tried
I have tried several tutorials and examples, with the same output, just different namespaces and class-names being skipped.
I have seen here that it all comes down to autoloading and reflection, but it didn't give me any practical hints what to do.
I also saw in some comments on github that downgrading to php 8.1 helps, but that didn't work for me. After a lot of fiddeling with the Dockerfile, it came down to the exact same error.
Also this question on SO didn't help. Seems to be very Laravel specific.
The suggestion here to have just one dummy class, yields pretty much the same error, tho there is no class skipped.
Just to make sure that I'm not having something really stupid, I verified that reflection is working with this code:
<?php
require './project/myTest.php';
$reflector = new ReflectionClass('La\Product');
$t = new La\Product();
echo $t->la . "\n";
var_dump($reflector->getProperties());
echo "\n";
print_r(array_map(fn($att) => $att->getName(), $reflector->getAttributes()));
var_dump( $reflector->getDocComment());
Which gave the expected output.
I think you are running into this issue: https://zircote.github.io/swagger-php/guide/faq.html#skipping-unknown-someclass
You've done pretty much everything correct, except for autoloading. In fact, in your manual example you've actually explicitely require
'd the test class file for the same reason - the class needs to be loaded for reflection to work.
There are two ways to get this basic test to work
a) Add myTest.php
as bootstrap option to the CL
This will do the require
for you, just like in your test code.
./vendor/bin/openapi -b project/myTest.php project/
b) Set up composer autoloading. Seems there is no composer.json in your setup. I suppose something like
{
"require": {
"zircote/swagger-php": "^4.8",
"doctrine/annotations": "^2.0"
},
"autoload": {
"psr-4": {
"La\\": "project/"
}
}
}
should work. Also means you can change your Dockerfile to a single composer command:
RUN ["composer", "install"]
It should be clear that option (b) is the more scalable :)
Final thing about autoloading is that PSR-4 requires the filename to match the classname, so you'll need to rename myTest.php
to Product.php
.