Option to set requirements and parameters directly from ApiDoc annotation

Sometimes required parameters are not used through routing but still they are mandatory. I wanted to have API with

resource.json?foo=bar&something=else

format, that was possible through QueryParam annotation or requirements in routing BUT!

There was no way to set dataType or description

This PR solves problem for me.

Side note: if you want to declare e.g. _format requirement through Annotation or any other param that is used in url ({foo} format) then it won't work. Because Bundle still overrides requirements and parameters after the constuctor in ApiDoc is called. This might be solved in separate PR by adding check if given requirements or parameters was already defined.
This commit is contained in:
Konrad Podgórski 2013-07-17 20:41:27 +02:00
parent 22cd63f9bd
commit 74d30d9e39
5 changed files with 129 additions and 2 deletions

View File

@ -153,6 +153,39 @@ class ApiDoc
} }
} }
if (isset($data['requirements'])) {
foreach ($data['requirements'] as $requirement) {
if (!isset($requirement['name'])) {
throw new \InvalidArgumentException('A "requirement" element has to contain a "name" attribute');
}
$name = $requirement['name'];
unset($requirement['name']);
$this->addRequirement($name, $requirement);
}
}
if (isset($data['parameters'])) {
foreach ($data['parameters'] as $parameter) {
if (!isset($parameter['name'])) {
throw new \InvalidArgumentException('A "parameter" element has to contain a "name" attribute');
}
if (!isset($parameter['dataType'])) {
throw new \InvalidArgumentException(sprintf(
'"%s" parameter element has to contain a "dataType" attribute',
$parameter['name']
));
}
$name = $parameter['name'];
unset($parameter['name']);
$this->addParameter($name, $parameter);
}
}
if (isset($data['output'])) { if (isset($data['output'])) {
$this->output = $data['output']; $this->output = $data['output'];
} }

View File

@ -89,6 +89,26 @@ class YourController extends Controller
public function postAction() public function postAction()
{ {
} }
/**
* @ApiDoc(
* description="Returns a collection of Object",
* requirements={
* {
* "name"="limit",
* "dataType"="integer",
* "requirement"="\d+",
* "description"="how many objects to return"
* }
* },
* parameters={
* {"name"="categoryId", "dataType"="integer", "required"=true, "description"="category id"}
* }
* )
*/
public function cgetAction($id)
{
}
} }
``` ```
@ -104,6 +124,10 @@ The following properties are available:
* `filters`: an array of filters; * `filters`: an array of filters;
* `requirements`: an array of requirements;
* `parameters`: an array of parameters;
* `input`: the input type associated to the method (currently this supports Form Types, classes with JMS Serializer * `input`: the input type associated to the method (currently this supports Form Types, classes with JMS Serializer
metadata, and classes with Validation component metadata) useful for POST|PUT methods, either as FQCN or as form type metadata, and classes with Validation component metadata) useful for POST|PUT methods, either as FQCN or as form type
(if it is registered in the form factory in the container). (if it is registered in the form factory in the container).

View File

@ -123,10 +123,10 @@
{% if not infos.readonly %} {% if not infos.readonly %}
<tr> <tr>
<td>{{ name }}</td> <td>{{ name }}</td>
<td>{{ infos.dataType }}</td> <td>{{ infos.dataType is defined ? infos.dataType : '' }}</td>
<td>{{ infos.required ? 'true' : 'false' }}</td> <td>{{ infos.required ? 'true' : 'false' }}</td>
<td>{{ infos.format }}</td> <td>{{ infos.format }}</td>
<td>{{ infos.description }}</td> <td>{{ infos.description is defined ? infos.description : '' }}</td>
</tr> </tr>
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View File

@ -28,6 +28,8 @@ class ApiDocTest extends TestCase
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertFalse($annot->getDeprecated()); $this->assertFalse($annot->getDeprecated());
$this->assertFalse(isset($array['description'])); $this->assertFalse(isset($array['description']));
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertNull($annot->getInput()); $this->assertNull($annot->getInput());
$this->assertFalse($array['authentication']); $this->assertFalse($array['authentication']);
} }
@ -47,6 +49,8 @@ class ApiDocTest extends TestCase
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertFalse($annot->getDeprecated()); $this->assertFalse($annot->getDeprecated());
$this->assertFalse(isset($array['description'])); $this->assertFalse(isset($array['description']));
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertNull($annot->getInput()); $this->assertNull($annot->getInput());
} }
@ -64,6 +68,8 @@ class ApiDocTest extends TestCase
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertFalse($annot->getDeprecated()); $this->assertFalse($annot->getDeprecated());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertNull($annot->getInput()); $this->assertNull($annot->getInput());
} }
@ -82,6 +88,8 @@ class ApiDocTest extends TestCase
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertFalse($annot->getDeprecated()); $this->assertFalse($annot->getDeprecated());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertEquals($data['input'], $annot->getInput()); $this->assertEquals($data['input'], $annot->getInput());
} }
@ -102,6 +110,8 @@ class ApiDocTest extends TestCase
$this->assertTrue($annot->isResource()); $this->assertTrue($annot->isResource());
$this->assertTrue($annot->getDeprecated()); $this->assertTrue($annot->getDeprecated());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertEquals($data['input'], $annot->getInput()); $this->assertEquals($data['input'], $annot->getInput());
} }
@ -121,6 +131,8 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertEquals($data['deprecated'], $array['deprecated']); $this->assertEquals($data['deprecated'], $array['deprecated']);
$this->assertEquals($data['input'], $annot->getInput()); $this->assertEquals($data['input'], $annot->getInput());
} }
@ -145,6 +157,8 @@ class ApiDocTest extends TestCase
$this->assertEquals(array('a-filter' => array()), $array['filters']); $this->assertEquals(array('a-filter' => array()), $array['filters']);
$this->assertTrue($annot->isResource()); $this->assertTrue($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertFalse(isset($array['requirements']));
$this->assertFalse(isset($array['parameters']));
$this->assertEquals($data['deprecated'], $array['deprecated']); $this->assertEquals($data['deprecated'], $array['deprecated']);
$this->assertNull($annot->getInput()); $this->assertNull($annot->getInput());
} }
@ -232,4 +246,45 @@ class ApiDocTest extends TestCase
$this->assertEquals($data['cache'], $array['cache']); $this->assertEquals($data['cache'], $array['cache']);
} }
public function testConstructWithRequirements()
{
$data = array(
'requirements' => array(
array(
'name' => 'fooId',
'requirement' => '\d+',
'dataType' => 'integer',
'description' => 'This requirement might be used withing action method directly from Request object'
)
)
);
$annot = new ApiDoc($data);
$array = $annot->toArray();
$this->assertTrue(is_array($array));
$this->assertTrue(isset($array['requirements']['fooId']));
$this->assertTrue(isset($array['requirements']['fooId']['dataType']));
}
public function testConstructWithParameters()
{
$data = array(
'parameters' => array(
array(
'name' => 'fooId',
'dataType' => 'integer',
'description' => 'Some description'
)
)
);
$annot = new ApiDoc($data);
$array = $annot->toArray();
$this->assertTrue(is_array($array));
$this->assertTrue(isset($array['parameters']['fooId']));
$this->assertTrue(isset($array['parameters']['fooId']['dataType']));
}
} }

View File

@ -198,4 +198,19 @@ class TestController
public function jmsReturnNestedOutputAction() public function jmsReturnNestedOutputAction()
{ {
} }
/**
* @ApiDoc(
* description="Returns a collection of Object",
* requirements={
* {"name"="limit", "dataType"="integer", "requirement"="\d+", "description"="how many objects to return"}
* },
* parameters={
* {"name"="categoryId", "dataType"="integer", "required"=true, "description"="category id"}
* }
* )
*/
public function cgetAction($id)
{
}
} }