-
Notifications
You must be signed in to change notification settings - Fork 118
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
@Relation annotation attributes are not available in the URL generators #174
Comments
We could easily add the Though I'm not sure about the feature |
Hi @adrienbrault, I'm not sure I understand exactly what you mean ... "as an expression variable for the route parameters". Could you give a code sample ?
Does anyone has the same need as us ? Thanks |
I think @adrienbrault intends something like (mutatis mutandis): /**
* [...]
* @Hateoas\Route(
* "nelmio_api_doc_index",
* absolute = true,
* parameters = "expr(object.getAttribute())"
* )
* [...]
*/
I'm also trying to integrate ApiDocBundle and HateoasBundle, even if it is not my priority right now. |
Hi and sorry to respond so late ! I understand the use of an expression variable but where this expression variable would be added, inside the In my use case everything I need is inside attributes of the In fact to be more generic what would be perfect and very flexible is to have an access to a the description of the current Relation (and the annotations it contains) in the Url Generator (or even better having an access to the whole context attached to the property which describes the relation). For example we could have an access to a interface HateoasUrlGeneratorInterface extends \Hateoas\UrlGenerator\UrlGeneratorInterface {
public function generate($name, array $parameters, $absolute = false);
function getCurrentRelation();
function setCurrentRelation(Relation $relation);
} An other solution could be to add a fourth parameter to the interface HateoasUrlGeneratorInterface extends \Hateoas\UrlGenerator\UrlGeneratorInterface {
public function generate($name, array $parameters, $absolute = false, Relation $relation = null);
} Then in the Url generator we have an access to the whole description of the relation for which one to generate a Url. class UrlGenerator implements UrlGeneratorInterface {
public function generate($name, array $parameters, $absolute = false, Relation $relation)
{
$relationAttributes = $relation->getAttributes();
if($relationAttributes['name'] === 'collection-doc') {
...
} else if($relationAttributes['name'] === 'entity-doc') {
...
}
}
} What do you think about this proposition ? |
@bgaillard I now have a clear picture of your point of view (I think at least). IMO, the current interface of On the other hand, adding a getter/setter for So why not solving this as already done for the Symfony Router? The generator parameters should be pre-filled with automatic value, which are not strictly /**
* [...]
* No duplication here.
* @Hateoas\Relation(
* "curies",
* attributes = {
* "name" = "entity-doc",
* "templated" = true
* },
* href = @Hateoas\Route(
* "nelmio_api_doc_index",
* absolute = true
* )
* )
*/
class SampleEntity { ... } And then into the generator you receive a more flexible parameters array: class UrlGenerator implements UrlGeneratorInterface {
// $parameters will contain _attributes key
public function generate($name, array $parameters, $absolute = false)
{
$relationAttributes = $parameters['_attributes'];
if($relationAttributes['name'] === 'collection-doc') {
$url = ...
} else if($relationAttributes['name'] === 'entity-doc') {
$url = ...
}
return $url;
}
} Note the What do you think? I can easily provide a PR for this. |
Hi @giosh94mhz and thanks for your quick response on this.
Yes, I agree with on this.
I'm not really sure I understand what you propose. If for example the /**
* @Hateoas\Relation(
* a = {},
* b = {},
* c = {},
* ...
* }
*/ What you propose is having an access to This seems strange to me and I think this solution has several disavantages :
In my opinion a solution with a specific software interface would be better, more flexible and easier to maintain.
Adding a Perhaps 2 different interfaces in Hateaos could do it :
// UrlGeneratorInterface.php
interface UrlGeneratorInterface {
public function generate($name, array $parameters, $absolute = false);
}
// RelationAwareUrlGeneratorInterface.php
interface RelationAwareUrlGeneratorInterface {
public function generate($name, array $parameters, $absolute = false, Relation $relation);
} Then a the moment of Url Generation (is it here https://github.com/willdurand/Hateoas/blob/master/src/Hateoas/Factory/LinkFactory.php ?) ... if($urlGenerator instanceof RelationAwareUrlGeneratorInterface) {
$urlGenerator->generate($name, $parameters, $isAbsolute, $relation);
} else if($urlGenerator instanceof UrlGeneratorInterface) {
$urlGenerator->generate($name, $parameters, $isAbsolute);
} What do you think about that ? |
No, is not what I mean. I agree with you that this is ugly. :) I mean that the generator will receive: $parameters = [
'your_routing_param' => 'param_value',
'_attributes' => [
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
]
] I'll open a PR for this if I get the time, so it may be clear. This seems magical, but it's actually in line with HAL ( If not choosing this way, I like the two interfaces idea, but I think that the These are my thought, but the maintainers will have the final word. :) |
@bgaillard I don't like the idea of making the url generator aware of the library's Configuration objects. Here's what I suggest you do: /**
* ...
*
* @Hateoas\Relation(
* "curies",
* attributes = {
* "name" = "collection-doc",
* "templated" = true
* },
* href = @Hateoas\Route(
* "nelmio_api_doc_index",
* absolute = true,
* parameters = { "anchor" = "get--rest-{rel}" }
* )
* )
* @Hateoas\Relation(
* "curies",
* attributes = {
* "name" = "entity-doc",
* "templated" = true
* },
* href = @Hateoas\Route(
* "nelmio_api_doc_index",
* absolute = true,
* parameters = { "anchor" = "get--rest-{rel}-id" }
* )
* )
*/
class SampleEntity { ... } public function generate($name, array $parameters, $absolute = false)
{
$anchor = '';
if (isset($parameters['anchor'])) {
$anchor = $parameters['anchor'];
unset($parameters['anchor']);
}
return parent::generate($name, $parameters, $absolute) . $anchor;
} And if you find that writing that annotation everytime is long and annoying, then you can introduce you own annotation for this: /**
* ...
*
* @YourVendor\Curie("collection-doc")
* @YourVendor\Curie("entity-doc")
*/
class SampleEntity { ... } And add a new Hateoas configuration extension: namespace YourVendor;
use Hateoas\Configuration\Metadata\ConfigurationExtensionInterface;
use Hateoas\Configuration;
class HateoasCurieExtension implements ConfigurationExtensionInterface
{
public function decorate(ClassMetadataInterface $classMetadata)
{
$relations = $this->getCurieRelations($classMetadata->getName());
foreach ($relations as $relation) {
$classMetadata->addRelation($relation);
}
}
private function getCurieRelations($className)
{
// use annotation driver to find your own annotation, and convert that to hateoas relation
$relations = [];
foreach ($annotations as $annotation) {
if (!$annotation instanceof MyVendor\Curie) {
continue;
}
$relations[] = new Configuration\Relation(
'curies',
new Configuration\Route('nelmio_api_doc_index', ['anchor' => 'get--rest-{rel}'], true),
null,
['name' => $annotation->name, 'templated' => true]
);
}
return $relations;
}
} |
@adrienbrault this is mind blowing! :) I haven't tough of the problem from this PoV. Anyway, since attributes are strictly related to the link and not a simple configuration, I don't see many issues in embedding the attributes inside the parameters for the generator sake; there are some drawback that I don't see? |
@giosh94mhz Yes, let's say you do that with this: /**
* ...
*
* @Hateoas\Relation(
* "curies",
* attributes = {
* "name" = "entity-doc",
* "templated" = true
* },
* href = @Hateoas\Route(
* "nelmio_api_doc_index",
* absolute = true
* )
* )
*/
class SampleEntity { ... } With the symfony router, the generated url would be |
@giosh94mhz A, ok now I understand well the solution you proposed. @adrienbrault Thanks for the code samples, I think defining a new annotation is a good idea for us.
Ok, in my opinion the Anyway playing with the |
Hi, I'm currently trying to generate multiple CURIE links having absolute hrefs.
Because I'm using Nelmio to document my APIs the CURIE absolute urls I have to generate must have the following structure.
Collection Resource :
http://myserver/doc/#get--rest-{rel}
.Entity Resource :
http://myserver/doc/#get--rest-{rel}-id
.To generate those CURIE links here are the Hateoas annotations I'm using on a sample entity class.
Because I have to generate absolute URLs I'm using the
@Hateoas\Route
annotation with the name of the Nelmio route (i.enelmio_api_doc_index
).Then, to generate my CURIE links I'm using a custom URL generator :
Notice the use of the
parameters
attribute in the@Hateoas\Route
annotations and then the retrieval of thename
parameter in my custom URL generator.Here, because the Hateoas generator does not have an access to the
attributes
attribute I'm forced to define my own conventions (i.e adding a custom parametername
in the@Hateoas\Route
annotation and then retrieve this parameter in my URL generator).It would be good to have an access to the
attributes
inside the Hateoas URL generators.What do you think about that ?
The text was updated successfully, but these errors were encountered: