Closed remoteclient closed 4 years ago
With this post I want to bring some clarity to the issue and show some investigation results. 'Therefore I will write two post with similar issues.
First:
I have a Pet
Entity which holds an array called $sexTypeChoices
and its getter.
/**
* @var array
*/
public static $sexTypeChoices = [
self::SEX_TYPE_FEMALE => 'sex_type.female',
self::SEX_TYPE_MALE => 'sex_type.male'
];
/**
* @return array
*/
public static function getSexTypeChoices(): array
{
return self::$sexTypeChoices;
}
This one has an extra endpoint where only this property delivered to the client (with extra serialization group).
<collectionOperation name="sex_type_choices">
<attribute name="method">GET</attribute>
<attribute name="access_control">is_granted('ROLE_MWS_NC_LIST')</attribute>
<attribute name="path">pets/sex_type_choices</attribute>
<attribute name="controller">MWS\NutritionCalculatorBundle\Controller\SexTypeChoices</attribute>
<attribute name="normalization_context">
<attribute name="groups">
<attribute name="group">mws_nc_sex_type_choices_read</attribute>
</attribute>
</attribute>
</collectionOperation>
If I call this endpint I get the correct result but the the swagger part which shows the expected result is empty:
[
{}
]
Before the update to v2.3.3 swagger showed the correct expected result like:
[
{
"sexTypeChoices": [
"string"
]
}
]
This bug was introduced with commit #2788
if (!$propertyMetadata->isReadable() && !$propertyMetadata->isWritable()) {
continue;
}
Since I get a correct result by calling the endpoint, the property IS readable. So either the condition is wrong or isReadable
returns a wrong result. As this was working before the commit I consider this a BC break.
Second: The second one is similar but also a bit more complicated since this is not only about non-mapped properties but also non-mapped nested classes (properties).
I have Dog
which inherits from Pet
. Pet
has a property called $analysis
which is of type Analysis
(non-mapped). Analysis holds another non-mapped property (arrayCollection) called RecipeItem
. This one holds a mapped property $ingredient
. So in the End Pet
holds several non-mapped nested classes.:
class Pet
{
...
/**
* @var Analysis
*/
private $analysis;
....
}
class Analysis
{
/**
* Analysis constructor.
*/
public function __construct()
{
$this->recipeItems = new ArrayCollection();
$this->nutrientTotal = new Requirement();
$this->nutrientPercentageTotal = new Requirement();
}
/**
* @var int
*/
private $id;
/**
* @var Pet
*/
private $pet;
/**
* @var RecipeItem[]
*/
private $recipeItems;
/**
* @var Requirement
*/
private $nutrientTotal;
/**
* @var Requirement
*/
private $nutrientPercentageTotal;
/**
* @var RequirementSatisfaction
*/
private $requirement;
...
}
class RecipeItem implements RecipeItemInterface
{
/**
* RecipeItem constructor.
*/
public function __construct()
{
$this->nutrientTotal = new Requirement();
}
/**
* @var NutritionDatabase
*/
private $ingredient;
/**
* @var int
*/
private $quantity;
/**
* @var string
*/
private $comparison;
/**
* @var Requirement
*/
private $nutrientTotal;
...
}
As Dog
inherits form Pet
I have a special endpoint which takes ingredients and quantity as input and outputs an analysis which shows if the ingridients of a recipe meets the requirement on nutrion for a specific pet in this case a dog.
<itemOperation name="dog_nutrition_analysis">
<attribute name="method">PUT</attribute>
<attribute name="access_control">is_granted('ROLE_MWS_NC_CREATE')</attribute>
<attribute name="path">/dogs/{id}/analysis</attribute>
<attribute name="controller">MWS\NutritionCalculatorBundle\Controller\Analysis</attribute>
<attribute name="normalization_context">
<attribute name="groups">
<attribute name="group">mws_nc_dog_analysis_read</attribute>
</attribute>
</attribute>
<attribute name="denormalization_context">
<attribute name="groups">
<attribute name="group">mws_nc_dog_analysis_write</attribute>
</attribute>
</attribute>
</itemOperation>
This is also giving me the correct results when I call the endpoint. Serialization groups are set properly. What is missing here is like above the expected output but also the correct body in which format and what properties to send. This behavior was introduced with v2.4.0. Expected Input shows:
{}
And the expected output shows:
{}
With v2.3.6 I get the correct expected input:
{
"analysis": {
"recipeItems": [
{
"ingredient": "string",
"quantity": 0
}
]
}
}
and also the correct expected output:
{
"analysis": {
"recipeItems": [
{
"ingredient": "string",
"quantity": 0,
"nutrientTotal": {
"TS": 0,
"GJ": 0,
"GCAL": 0,
"ZE": 0,
"ZF": 0,
"ZK": 0,
"ZB": 0,
"F182": 0,
"F183": 0,
"F205": 0,
"F226": 0,
"MCA": 0,
"MP": 0,
"MMG": 0,
"MNA": 0,
"MK": 0,
"MCL": 0,
"MFE": 0,
"MCU": 0,
"MZN": 0,
"MMN": 0,
"MJ": 0,
"VA": 0,
"VD": 0,
"VE": 0,
"VB1": 0,
"VB2": 0,
"VB3": 0,
"VB5": 0,
"VB6": 0,
"VB7": 0,
"VB9G": 0,
"VB12": 0,
"EARG": 0,
"EHIS": 0,
"EILE": 0,
"EMET": 0,
"ECYS": 0,
"EMETECYS": 0,
"ELEU": 0,
"ELYS": 0,
"EPHE": 0,
"EPHEETYR": 0,
"ETHR": 0,
"ETRP": 0,
"EVAL": 0,
"EP": 0,
"GMCAMP": 0,
"GZKTS": 0,
"GZBTS": 0,
"GZFTS": 0,
"GZMTS": 0,
"GGJDENS": 0,
"GKAB": 0,
"GHARNPH": 0
}
}
],
"nutrientTotal": {
"TS": 0,
"GJ": 0,
"GCAL": 0,
"ZE": 0,
"ZF": 0,
"ZK": 0,
"ZB": 0,
"F182": 0,
"F183": 0,
"F205": 0,
"F226": 0,
"MCA": 0,
"MP": 0,
"MMG": 0,
"MNA": 0,
"MK": 0,
"MCL": 0,
"MFE": 0,
"MCU": 0,
"MZN": 0,
"MMN": 0,
"MJ": 0,
"VA": 0,
"VD": 0,
"VE": 0,
"VB1": 0,
"VB2": 0,
"VB3": 0,
"VB5": 0,
"VB6": 0,
"VB7": 0,
"VB9G": 0,
"VB12": 0,
"EARG": 0,
"EHIS": 0,
"EILE": 0,
"EMET": 0,
"ECYS": 0,
"EMETECYS": 0,
"ELEU": 0,
"ELYS": 0,
"EPHE": 0,
"EPHEETYR": 0,
"ETHR": 0,
"ETRP": 0,
"EVAL": 0,
"EP": 0,
"GMCAMP": 0,
"GZKTS": 0,
"GZBTS": 0,
"GZFTS": 0,
"GZMTS": 0,
"GGJDENS": 0,
"GKAB": 0,
"GHARNPH": 0
},
"nutrientPercentageTotal": {
"TS": 0,
"GJ": 0,
"GCAL": 0,
"ZE": 0,
"ZF": 0,
"ZK": 0,
"ZB": 0,
"F182": 0,
"F183": 0,
"F205": 0,
"F226": 0,
"MCA": 0,
"MP": 0,
"MMG": 0,
"MNA": 0,
"MK": 0,
"MCL": 0,
"MFE": 0,
"MCU": 0,
"MZN": 0,
"MMN": 0,
"MJ": 0,
"VA": 0,
"VD": 0,
"VE": 0,
"VB1": 0,
"VB2": 0,
"VB3": 0,
"VB5": 0,
"VB6": 0,
"VB7": 0,
"VB9G": 0,
"VB12": 0,
"EARG": 0,
"EHIS": 0,
"EILE": 0,
"EMET": 0,
"ECYS": 0,
"EMETECYS": 0,
"ELEU": 0,
"ELYS": 0,
"EPHE": 0,
"EPHEETYR": 0,
"ETHR": 0,
"ETRP": 0,
"EVAL": 0,
"EP": 0,
"GMCAMP": 0,
"GZKTS": 0,
"GZBTS": 0,
"GZFTS": 0,
"GZMTS": 0,
"GGJDENS": 0,
"GKAB": 0,
"GHARNPH": 0
},
"requirement": {
"TS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GJ": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GCAL": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ZE": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ZF": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ZK": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ZB": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"F182": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"F183": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"F205": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"F226": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MCA": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MP": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MMG": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MNA": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MK": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MCL": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MFE": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MCU": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MZN": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MMN": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"MJ": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VA": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VD": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VE": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB1": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB2": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB3": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB5": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB6": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB7": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB9G": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"VB12": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EARG": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EHIS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EILE": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EMET": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ECYS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EMETECYS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ELEU": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ELYS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EPHE": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EPHEETYR": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ETHR": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"ETRP": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EVAL": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"EP": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GMCAMP": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GZKTS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GZBTS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GZFTS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GZMTS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GGJDENS": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GKAB": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
},
"GHARNPH": {
"safeUpperLimit": 0,
"recommendedAllowance": 0,
"minimalRequirement": 0
}
}
}
}
If I remove the Lines from #2788 the expected output is also empty, but the expected output shows:
{
"analysis": "string"
}
So this faulty swagger output does not only come from the linked commit. I think something is messed up in the metadataFactory
. Like above as this is a change in behavior I would consider this a BC break
@remoteclient Do you think the proposal in api-platform/api-platform#1197 will address this? :smile:
@teohhanhui The proposal looks promising, as it seems that it brings back the features that where gone from v2.3 to v2.4
The points:
they should require no ID in any context they should require no IRI in any context they should require no path to resource in any context
also used to work in v2.3. I just set a fake Id. For the last two points I worked around by decorating the IriConverter like here. With this I was able to hide non mapped and/or nested entities from docs but could use serialization with groups.
@teohhanhui I updated to APIP 2.5.4 today. Sadly my issue isn't fixed. The swagger output stays empty.
@remoteclient Can you check if #3273 (merged into master
) has changed anything on this front?
@teohhanhui Sorry for the late reply.... Sad to say, but I don't think so. I switched the core to dev-master and could not see any difference in swagger output.
Sorry for not taking a deeper look earlier. To respond to https://github.com/api-platform/core/issues/2868#issuecomment-505013132:
This seems to have to do with using a static method, which is not supported by PropertyInfo
: https://github.com/symfony/symfony/pull/21331 (see also https://github.com/symfony/symfony/pull/21331#issuecomment-274462136)
As for https://github.com/api-platform/core/issues/2868#issuecomment-505026740, I've sent you a PM on Symfony Slack. Let's figure this out!
I don't use the static methods anymore in favor of object classes.
https://github.com/api-platform/core/issues/2868#issuecomment-505026740 is more important. Whats missing here are input and output in swagger for unmapped related classes.
What I don't understand is that all is normalized/denormlized correctly by the serializer... So the serializer can "walk" across the related entities and get all properties while swagger cannot.
https://github.com/api-platform/core/issues/2868#issuecomment-505026740 seems to be the same as #3146
I am closing this as it got meŕged in APIP v 2.5.5. There is one issue left. Swagger / OpenApi shows the example value only in swagger version2. There are some issues targeting this in the OpenApi repo.
As the title suggests, non-mapped properties are not shown in swagger output anymore. There are different scenarios. Sometimes one entity has a non-mapped property, some entities have other non-mapped entities with naturally also non-mapped properties. They all have in commen, that they don't appear in swagger anymore. They also have propper getters and setters. Serialization/Dezerialization of them are working like before.