Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: HTTP Response Code and Include File #71

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions Annotation/ApiDoc.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ class ApiDoc
*/
private $route;

/**
* Stores HTTP Response Codes and a description
* @var array
*/
private $responseCodes;

/**
* An optional Markdown file to include with a long description.
* @var String
*/
private $fileToInclude;

public function __construct(array $data)
{
if (isset($data['input'])) {
Expand All @@ -103,6 +115,14 @@ public function __construct(array $data)
$this->return = $data['return'];
}

if (isset($data['responseCodes'])) {
$this->responseCodes = $data['responseCodes'];
}

if (isset($data['include'])) {
$this->fileToInclude = $data['include'];
}

$this->isResource = isset($data['resource']) && $data['resource'];
}

Expand Down Expand Up @@ -241,6 +261,39 @@ public function getRoute()
/**
* @return array
*/
public function getResponseCodes()
{
return $this->responseCodes;
}

/**
* @param array
*/
public function addResponseCode($c)
{
$this->responseCodes = array_merge($this->responseCodes, $c);
}

/**
* @return String
*/
public function getFileToInclude()
{
return $this->fileToInclude;
}

/**
* @param String $newFileToInclude
*/
public function setFileToInclude($newFileToInclude)
{
$this->fileToInclude = $newFileToInclude;
}

/**
* @return array
* @throws \InvalidArgumentException if the file to be included is not readable
*/
public function toArray()
{
$data = array(
Expand Down Expand Up @@ -272,6 +325,14 @@ public function toArray()
$data['response'] = $response;
}

if ($responseCodes = $this->responseCodes) {
$data['responseCodes'] = $responseCodes;
}

if ($fileToInclude = $this->fileToInclude) {
$data['fileToInclude'] = $fileToInclude;
}

return $data;
}
}
7 changes: 7 additions & 0 deletions Extractor/ApiDocExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,13 @@ protected function extractData(ApiDoc $annotation, Route $route, \ReflectionMeth
$annotation->setMethod($route->getRequirement('_method') ?: 'ANY');
$annotation->setUri($route->getPattern());

// Include File
$fileToInclude = $annotation->getFileToInclude();
if (!empty($fileToInclude)) {
$refl = new \ReflectionClass($method->class);
$annotation->setFileToInclude(dirname($refl->getFileName()) . DIRECTORY_SEPARATOR . $fileToInclude);
}

return $annotation;
}

Expand Down
8 changes: 8 additions & 0 deletions Formatter/HtmlFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,17 @@ public function setTemplatingEngine(EngineInterface $engine)

/**
* {@inheritdoc}
* @throws \InvalidArgumentException if the file to be included cannot be loaded.
*/
protected function renderOne(array $data)
{
if (!empty($data['fileToInclude'])) {
if (!is_readable($data['fileToInclude'])) {
throw new \InvalidArgumentException("Could not open: {$fileToInclude}");
}
$data['fileToInclude'] = file_get_contents($data['fileToInclude']);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not simply using the |markdown filter to do the rendering part, passing the content of the file here ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


return $this->engine->render('NelmioApiDocBundle::resource.html.twig', array_merge(
array('data' => $data, 'displayContent' => true),
$this->getGlobalVars()
Expand Down
10 changes: 10 additions & 0 deletions Formatter/MarkdownFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class MarkdownFormatter extends AbstractFormatter
{
/**
* {@inheritdoc}
* @throws \InvalidArgumentException if the file to be included cannot be loaded.
*/
protected function renderOne(array $data)
{
Expand All @@ -33,6 +34,15 @@ protected function renderOne(array $data)
}
}

if (!empty($data['fileToInclude'])) {
if (!is_readable($data['fileToInclude'])) {
throw new \InvalidArgumentException("Could not open: {$fileToInclude}");
}

$fileContents = file_get_contents($data['fileToInclude']);
$markdown .= $fileContents;
}

if (isset($data['requirements']) && !empty($data['requirements'])) {
$markdown .= "#### Requirements ####\n\n";

Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,46 @@ The following properties are available:
* `input`: the input type associated to the method, currently this supports Form Types, and classes with JMS Serializer
metadata, useful for POST|PUT methods, either as FQCN or as form type (if it is registered in the form factory in the container)

* `responseCodes`: an array of HTTP response codes and a description of when that response is returned; Example:

``` php
<?php

class YourController
{
/**
* @ApiDoc(
* responseCodes={
* 200="Returned when successful",
* 403="Returned when the user is not authorized to say hello"},
* )
*/
public function myFunction()
{
// ...
}
}
```

* `include`: filename of a markdown formatted file to be included for longer documentation; This is relative to the location of the controller, i.e.

``` php
<?php

class YourController
{
/**
* @ApiDoc(
* include="../Resources/doc/myFunction.md"
* )
*/
public function myFunction()
{
// ...
}
}
```

Each _filter_ has to define a `name` parameter, but other parameters are free. Filters are often optional
parameters, and you can document them as you want, but keep in mind to be consistent for the whole documentation.

Expand Down
25 changes: 24 additions & 1 deletion Resources/views/method.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@
{% if data.documentation is defined and data.documentation is not empty %}
<h4>Documentation</h4>
<div>{{ data.documentation|extra_markdown }}</div>
{% if data.fileToInclude is defined and data.fileToInclude is not empty %}
<div>{{ data.fileToInclude|extra_markdown }}</div>
{% endif %}
{% endif %}

{% if data.responseCodes is defined and data.responseCodes is not empty %}
<h4>Response Codes</h4>
<table class="fullwidth">
<thead>
<tr>
<th>Response Code</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for response_code, description in data.responseCodes %}
<tr>
<td><a href="http://en.wikipedia.org/wiki/HTTP_{{ response_code }}" target="_blank">{{ response_code }}<a/></td>
<td>{{ description }}</td>
</tr>
{% endfor %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the <tr> tag should be closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. /me embarassed

</tbody>
</table>
{% endif %}

{% if data.requirements is defined and data.requirements is not empty %}
Expand Down Expand Up @@ -136,7 +159,7 @@
<p class="tuple">
<input type="text" class="key" value="{{ name }}" placeholder="Key" />
<span>=</span>
<input type="text" class="value" placeholder="{% if infos.description is defined %}{{ infos.description }}{% else %}Value{% endif %}" /> <span class="remove">-</span>
<input type="text" class="value" placeholder="{% if infos.default is defined %}{{ infos.default }}{% elseif infos.description is defined %}{{ infos.description }}{% else %}Value{% endif %}" /> <span class="remove">-</span>
</p>
{% endfor %}
{% endif %}
Expand Down
34 changes: 34 additions & 0 deletions Tests/Annotation/ApiDocTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,38 @@ public function testConstructNoFiltersIfFormTypeDefined()
$this->assertEquals($data['description'], $array['description']);
$this->assertEquals($data['input'], $annot->getInput());
}

public function testConstructWithHTTPResponseCodes()
{
$data = array(
'description' => 'Heya',
'responseCodes' => array(
200 => "Returned when successful",
403 => "Returned when the user is not authorized"
)
);

$annot = new ApiDoc($data);
$array = $annot->toArray();

$this->assertTrue(is_array($array));
$this->assertTrue(is_array($array['responseCodes']));
foreach ($data['responseCodes'] as $code => $message) {
$this->assertEquals($array['responseCodes'][$code], $message);
}
}

public function testConstructWithFileToInclude()
{
$data = array(
'description' => 'Heya',
'include' => 'file/here/'
);

$annot = new ApiDoc($data);
$array = $annot->toArray();

$this->assertTrue(is_array($array));
$this->assertEquals($data['include'], $array['fileToInclude']);
}
}