API Platform 3 non-identifier path parameters - symfony

In previous versions of API Platform you've been able to define the path for an operation with route parameters in the standard Symfony style, i.e. /resource/{id}/{parameter}
In the newest version of API Platform (v3) the configuration of these paths seems to have changed so that you need to create a Link() metadata for each parameter which maps a them directly to a property, which is in turn used by doctrine alter the queries dynamically. The issue is that I don't want {parameter} to be LInk-ed at all as it does not directly represent a property.
Is there a way to declare a parameter as a non identifier? Or as a non Link()? If you don't define a uriVariables entry for it then it assumes that it is the id for the mapped entity.

I had a similar issue and i resolved it using a fake public property in the entity itself (api-platform 2.7 with the flag to 3), and mapping the {parameter} to that property
'id' => 'fake_public_property'

Related

way to override #RedisHash value in configuration

I'm using a framework which is based spring-data-redis, and the framework was using #RedisHash to set value the redis key uses. Is there a way to override the value set in #RedisHash?
I'm tring to use KeyspaceSettings to do that, but it seems not working. I've noticed the official documentation says "#RedisHash has the highest priority", is it the truth?
However, the annotated keyspace supersedes any other configuration.
Yes, you can choose the name of the hash adding a name parameter like this:
#RedisHash("name_hash")

API Platform custom IRI with value objects

I am currently trying to create a custom IRI for one of my entities in API Platform.
I know there is page in the documentation describing how to use a custom IRI (https://api-platform.com/docs/core/identifiers/), but I can't get it working.
My entity uses a value object for the id (currently used for IRI) and also for the name (should be used for IRI). But the values themself are priviate and scalar in the entity.
API Platform seems to get the information what should be used as the identifier, from my XML Doctrine mapping. I already tried to overwrite it by usung annotations, attributues and YAML definitions. Without luck.
The returned error reads:
preg_match(): Argument #2 ($subject) must be of type string
(at this point it receives the value object instead of the actual value)
best regards,
spigandromeda
I solved my problem.
To explain the solution, I have to dig a little into API Platform response generation.
API platform generates an IRI for every entity it returns (colelction and item operation)
it's using the Symfony router go generate the URI
all the necessary information can draw API Platform from different sources (YAML, XML, annotations, attributes)
the information include the identifier(s) defined for the entities resource
API Platform gets the value for the identifier via Symfony property accessor
because the property accessor is using getters before accessing private properties via reflection, it will return the VO
an ordinary VO cannot be used by the Symfony URL generator to create the URL
As I explained, I am using a VO for my Id as well. So I tried to figure out why it was working with the Id VO but not with the name VO.
Simple answer: the Id VO implemented the __toString method and the name VO didn't. So the solution was to let the name VO implement this method as well.
It was interesing to dig into the internal process of API Platform, but I also feel a little stupid :D

oData v4 - ordering outer entity on property in related one-to-many entities

I have an oData model with a couple of one-to-many relationship, say person->addresses and person->driving-licences. I would like to be able to sort the result set based on properties in the address entity and driving licence entity. As there could be more than one address, I would initially select a single item from the addresses set, based on a property called IsPrimary. As there could be more that one driving licence, I would select the 'UK' driving licence. Is this possible?
I was hoping I could do something like:
/people?$expand=addresses($filter=isPrimary eq true),drivinglicences($filter=country eq 'UK')&$orderby=addresses/postcode,drivinglicences/active
Unfortunately I get the following error:
"The query specified in the URI is not valid. The parent value for a property access of a property 'isPrimary' is not a single value. Property access can only be applied to a single value."
Does anyone know if what I'm trying to do is supported by the spec? Or whether it is an issue with my query? Or whether it is an issue with the .NET library.
I'm using:
Microsoft.AspNet.OData - 7.2.3
Many Thanks.
What you see here is by design, or rather not supported by the specification, the error message even highlights the only type of expressions supported:
The query specified in the URI is not valid. The parent value for a property access of a property 'isPrimary' is not a single value. Property access can only be applied to a single value.
So the simplest solution is to modify the API either to include a Function bound to the people collection that applies the $filter or $order directly, or a Function that returns the data in a new shape, one that only has perhaps a singleton PrimaryAddress property. How you include driving license in this result is up to you, it could even be a parameter to the function, perhaps your people controller has a queryable function with this signature:
[EnableQuery]
public IHttpActionResult WithLicences(string countryCode)
However that is out of the scope of OPs question about specific syntax support
Although it seems like an important feature, we must remember that $select (Projection) and $filter are evaluated at different points in time, OData queries follow a similar execution sequence to SQL however the filter criteria and $orderby are evaluated separately, and the projection of the resultset is the last evaluation to be applied.
Due to $filter and $orderby being applied independently, neither concept is even aware of the other and as such neither can reference or assume to be applied before the other.
You can prove this by specifying a field in the $orderby and/or $filter that is not included in the $select, you can even reference singleton navigation fields that are not included in an $expand and the query will evaluate correctly.
The OData spec is similar to a law document, in that to properly understand and apply it we need to understand the original intent of the authors. We can get an initial understanding from the early listing of Addressing Entities
Addressing Entities describes functions that can be bound to collections or entities that return either a single entity or a collection of entities
By allowing special provision of custom functions to be applied the authors are encouraging API designers to provide natural extensions to their resource endpoints that can facilitate the execution of pre-determined queries that may be otherwise complex or problematic to express in pure OData query syntax.
In other words, we are encouraged to customise our APIs to make them easier for the end process to consume, and to guide the consuming developer to make the best use of the API, they shouldn't have to discover everything from first principals.
To achieve OPs type of query in pure SQL would still require either a nested lookup, CTE or self join... advanced syntax. In OData v4, the specification does not provide a syntax for targeting specific items within a collection for path expressions (of which $orderby derives from)
5.1.1.15 Path Expressions
Properties and navigation properties of the entity type of the set of resources that are addressed by the request URL can be used as operands or function parameters, as shown in the preceding examples.
Properties of complex properties can be used via the same syntax as in resource paths, i.e. by specifying the name of a complex property, followed by a forward slash (/) and the name of a property of the complex property, and so on,
Properties and navigation properties of entities related with a target cardinality 0..1 or 1 can be used by specifying the navigation property, followed by a forward slash (/) and the name of a property of the related entity, and so on.
If a complex property is null, or no entity is related (in case of target cardinality 0..1), its value, and the values of its components, are treated as null.
RE: I couldn't find anything explicit in the spec. :)
That is the very thing about the OData specification,the specification does not list what is not supported, only what should be supported. So by omission, if you cannot find a reference to how to do something, then that something is not required to be supported.
Introduction http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_Introduction ... This specification defines a set of recommended (but not required) rules for constructing URLs to identify the data and metadata exposed by an OData service as well as a set of reserved URL query string operators, which if accepted by an OData service, MUST be implemented as required by this document.
This has been on ongoing discussion held in may threads, recently https://stackoverflow.com/a/55324393/1690217
Many people complain that this is surely a fundamental feature of a data access platform, however it is important to respect the original intent of the OData platform and keep our APIs simple by providing customised endpoints to suit our business domain.

Defining default #GeneratedValue Strategy for Symfony MakerBundle

When using the MakerBundle in Symfony (4) to create new entity (make:entity EntityName), an id is generated by default with annotation (if annotations enabled) #GeneratedValue.
#GeneratedValue means #GeneratedValue(strategy="AUTO").
According to the Doctrine documentation, the AUTO strategy is supposed to use SERIAL type for the id in PostgreSQL. But, I do not know why in my case, the AUTO strategy use SEQUENCE for the id.
Then, I can force it to use SERIAL by changing by hand into #GeneratedValue(strategy="IDENTITY") which means using SERIAL type in PostgreSQL.
Is there any way to change the default #GeneratedValue annotation created by the MakerBundle for the new entities to be created with the #GeneratedValue(strategy="IDENTITY") annotation ?
What you could possibly do is decorate \Symfony\Bundle\MakerBundle\Doctrine\EntityClassGenerator which is registered as a service named maker.entity_class_generator in vendor/symfony/maker-bundle/src/Resources/config/services.xml and override its generateEntityClass method to make a different call on the Generator's generateClass method, specifically the file path could be changed there.
Seems like the file path there could be relative or absolute, so with some trial and error you could get it to output the annotation you want. The template that the maker bundle uses now is at vendor/symfony/maker-bundle/src/Resources/skeleton/doctrine/Entity.tpl.php, and it's pretty straightforward to modify.

ASP.NET OData query returns properties with empty values for virtual properties in code first models

I'm currently building a ASP.NET OData service which uses code first with EF5. When I do the query of a entity, it is returned as JSON along with empty values for the related entities.
I want the related entities attributes not to be included in the returned JSON for the entity query unless 'Include' is explicitly mentioned.
Is there a way to achieve this?
You have to enable lazy loading by setting the related members as virtual

Resources