Hydrate joined Entities with Api-Platform - symfony

I m building my first rest API with Api-Platform for an AngularJs app,
I want to get all my Project entity like juste here (with my url /projects):
{
"#context": "/contexts/Project",
"#id": "/projects",
"#type": "hydra:PagedCollection",
"hydra:totalItems": 19,
"hydra:itemsPerPage": 30,
"hydra:firstPage": "/projects",
"hydra:lastPage": "/projects",
"hydra:member": [
{
"#id": "/projects/1",
"#type": "Project",
"name": "test1",
"parent": null,
"createdAt": "2014-12-22T11:38:13+01:00",
"updatedAt": null,
"deletedAt": null
},
{
"#id": "/projects/2",
"#type": "Project",
"name": "test2",
"parent": null,
"createdAt": "2014-12-22T17:02:50+01:00",
"updatedAt": null,
"deletedAt": null
},
{
"#id": "/projects/3",
"#type": "Project",
"name": "test3",
"parent": "/projects/2",
"createdAt": "2014-12-22T18:28:50+01:00",
"updatedAt": null,
"deletedAt": null
}
]
}
But as you can see my Projects can have parent, so I got a reference of my parent Project ( like this /projects/2 )
Can I get directly a Project Object in Json instead of reference like this ?
{
"#id": "/projects/3",
"#type": "Project",
"name": "test3",
"parent": {
"#id": "/projects/2",
"#type": "Project",
"name": "test2",
"parent": null,
"createdAt": "2014-12-22T17:02:50+01:00",
"updatedAt": null,
"deletedAt": null
},
"createdAt": "2014-12-22T18:28:50+01:00",
"updatedAt": null,
"deletedAt": null
}
This is a good pratical of Rest APi ?

API Platform has a built-in function for embedding relations in the parent JSON document.
Your entity will look like:
namespace AppBundle\Entity;
use Symfony\Component\Serializer\Annotation\Groups;
class Project
{
private $id;
/** #Groups({"embed"}) */
private $parent;
/** #Groups({"embed"}) */
private $name;
/** #Groups({"embed"}) */
private $createdAt;
// ...
}
And the service definition:
# app/config/services.yml
services:
# ...
resource.offer:
parent: api.resource
arguments: [ 'AppBundle\Entity\Offer' ]
calls:
- method: initNormalizationContext
arguments: [ { groups: [ embed ] } ]
tags: [ { name: api.resource } ]
Be careful, it will embed the parent as well as the parent of the parent and so on. If you want to change this, you need to create a custom normalizer. It will be more straightforward when Symfony 3.1 will be released thanks to the new #MaxDepth annotation.

Related

Completely override response json-ld #context

Is it possible to override completely the #context of an api-platform ld+json response ?
(I had to replace the localhost urls with <base-api-url>, otherwise the question was marked as spam)
I have this PHP Dto :
#[ApiResource(
shortName: 'Account',
types: [
'https://www.w3.org/ns/activitystreams',
],
operations: [
new Get(
uriTemplate: '/accounts/{id}',
uriVariables: [
'id' => new Link(
fromProperty: 'id',
fromClass: Account::class,
)
],
controller: GetPersonController::class,
normalizationContext: [
'groups' => ['activitypub'],
'jsonld_embed_context' => true
],
provider: AccountStateProvider::class
)
]
)]
class Person
{
#[ApiProperty(identifier: true)]
#[Groups(['activitypub'])]
public string $id;
#[Groups(['activitypub'])]
public string $type = "Person";
#[Groups(['activitypub'])]
public string $following;
[...]
And the response is :
{
"#context": {
"#vocab": "<base-api-url>docs.jsonld#",
"hydra": "http://www.w3.org/ns/hydra/core#",
"id": "Account/id",
"type": "Account/type",
"following": "Account/following",
"followers": "Account/followers",
"inbox": "Account/inbox",
"outbox": "Account/outbox",
"name": "Account/name",
"preferredUsername": "Account/preferredUsername",
"summary": "Account/summary",
"url": "Account/url",
"published": "Account/published"
},
"#id": "/accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409",
"#type": "https://www.w3.org/ns/activitystreams",
"id": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409",
"type": "Person",
"following": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/followings",
"followers": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/followers",
"inbox": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/inbox",
"outbox": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/outbox",
"name": "Test User",
"preferredUsername": "testuser",
"summary": "",
"url": "https://localhost/#testuser",
"published": "2023-01-28T18:39:24+00:00"
}
What I need is :
{
"#context": [
"https://www.w3.org/ns/activitystreams"
],
"id": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409",
"type": "Person",
"following": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/followings",
"followers": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/followers",
"inbox": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/inbox",
"outbox": "<base-api-url>accounts/0185f9ad-5602-7aef-bac3-1a4d1b32a409/outbox",
"name": "Test User",
"preferredUsername": "testuser",
"summary": "",
"url": "https://localhost/#testuser",
"published": "2023-01-28T18:39:24+00:00"
}

The language expression property '0' can't be evaluated, property name must be a string - ARM Template error while adding Key Vault access policy

I've been working on an issue and seem to be stuck, so asking on so in case anyone can help.
To describe the issue, I've got an existing Azure Key Vault setup, and wish to add a number of access policies to this resource group. It needs to be conditional as if the function name is "false" then that function should not be added to key vault access policy.
variable section:
"variables": {
"functionAccess": {
"value": [
{
"name": "[parameters('Function_1')]"
},
{
"name": "[parameters('Function_2')]"
},
{
"name": "[parameters('Function_3')]"
}
]
}
}
My Template :
{
"apiVersion": "2016-10-01",
"condition": "[not(equals(variables('functionAccess')[CopyIndex()].name, 'false'))]",
"copy": {
"batchSize": 1,
"count": "[length(variables('functionAccess'))]",
"mode": "Serial",
"name": "accessPolicies"
},
"name": "[concat(parameters('KeyVault_Name'), '/add')]",
"properties": {
"accessPolicies": [
{
"tenantId": "[subscription().tenantId]",
"objectId": "[if(not(equals(variables('functionAccess')[CopyIndex()].name, 'false')), reference(concat('Microsoft.Web/sites/', variables('functionAccess')[CopyIndex()].name), '2016-08-01', 'Full').identity.principalId, json('null'))]",
"permissions": {
"keys": [
"get",
"list"
],
"secrets": [
"get",
"list"
],
"certificates": [
"get",
"list"
]
}
}
]
},
"type": "Microsoft.KeyVault/vaults/accessPolicies"
}
When I deploy my ARM template for the azure key vault I got this error message:
The language expression property '0' can't be evaluated, property name must be a string.
also tried below, but same error:
{
"apiVersion": "2018-02-14",
"name": "[concat(parameters('KeyVault_Name'), '/add')]",
"properties": {
"copy": [
{
"batchSize": 1,
"count": "[length(variables('functionAccess'))]",
"mode": "serial",
"name": "accessPolicies",
"input": {
"condition": "[not(equals(variables('functionAccess')[copyIndex('accessPolicies')].name, 'false'))]",
"tenantId": "[subscription().tenantId]",
"objectId": "[if(not(equals(variables('functionAccess')[copyIndex('accessPolicies')].name, 'false')), reference(concat('Microsoft.Web/sites/', variables('functionAccess')[copyIndex('accessPolicies')].name), '2016-08-01', 'Full').identity.principalId, json('null'))]",
"permissions": {
"keys": [
"get",
"list"
],
"secrets": [
"get",
"list"
],
"certificates": [
"get",
"list"
]
}
}
}
]
},
"type": "Microsoft.KeyVault/vaults/accessPolicies"
}
There are a few options for dealing with filtering an array for copy operation. I deploy my ARM templates from PowerShell scripts and use PowerShell to setup parameter values. When I need special logic handle different inputs for different environments, I let PowerShell handle it.
If you must handle the filtering in ARM and you have the option to input a CSV list of functions, then perhaps the following will work. You can then use the functionAccessArray to iterate over in the copy operation.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
"functionAccessCsv": "Function-0,Function-1,false,Function-4,false,Function-6,Function-7",
"functionAccessFiltered": "[replace(replace(variables('functionAccessCsv'), 'false', ''), ',,', ',')]",
"functionAccessArray": "[split(variables('functionAccessFiltered'), ',')]"
},
"resources": [
],
"outputs": {
"functionAccessCsvFiltered": {
"type": "string",
"value": "[variables('functionAccessFiltered')]"
},
"functionAccessArray": {
"type": "array",
"value": "[variables('functionAccessArray')]"
}
}
}
The result:
I just had the same issue. By using an array parameter with a default value instead of a variable, I got it to work.
"parameters": {
"functionAccess": {
"type": "array",
"defaultValue": [
"value1",
"value2",
"value3"
]
}
}

Symfony Return child objects depend of some property

Im using Symfony 4 + Api Platform. I have an entity (Insurance) that it is relationed with another entity (MediaObject). When I try to GET some item of Insurance, it is returning all the MediaObjects items that they are relationed with it. However, I dont want to return all the MediaObjects. I need MediaObjects where deletedAt is null.
How can I fix that?
I have a DoctrineExtension where I coded:
$queryBuilder->join(sprintf('%s.mediaObjects', $rootAlias), 'mo');
$queryBuilder->andWhere(sprintf('%s.deletedAt IS NULL', $rootAlias));
$queryBuilder->andWhere('mo.deletedAt IS NULL');
but nothing happens. It is still returning all items.
[
{
"id": 1,
"mediaObjects": [
{
"id": 5,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T09:36:05+02:00",
"updatedAt": "2018-07-20T09:36:05+02:00",
"deletedAt": "2018-07-20T14:20:34+02:00"
},
{
"id": 10,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T11:01:38+02:00",
"updatedAt": "2018-07-20T14:04:42+02:00",
"deletedAt": "2018-07-20T14:20:34+02:00"
},
{
"id": 4,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T09:35:56+02:00",
"updatedAt": "2018-07-20T14:04:00+02:00",
"deletedAt": "2018-07-20T14:15:09+02:00"
},
{
"id": 6,
"mimetype": "image/jpeg",
"type": "INSURANCE",
"createdAt": "2018-07-20T09:36:13+02:00",
"updatedAt": "2018-07-20T14:15:49+02:00",
"deletedAt": null
}
],
"expirationDate": "2018-07-19T08:25:29+02:00",
"policy": "Verduras",
"producerName": "Aseguradoras S.L.",
"contactEmail": "testsingfact+aseguradora1#gmail.com",
"contactPhone": "700000001",
"quantity": 1200,
"type": "CARGO",
"coverageExceptions": "Caidas",
"createdAt": "2018-07-19T10:27:22+02:00",
"updatedAt": "2018-07-19T13:06:31+02:00",
"deletedAt": null
}
]
You should use conditional join and apply filter to the joining collection not to the whole set:
$queryBuilder->join(sprintf('%s.mediaObjects', $rootAlias), 'mo', 'WITH', 'mo.deletedAt IS NULL');
$queryBuilder->andWhere(sprintf('%s.deletedAt IS NULL', $rootAlias));
Keep in mind this query will not return insurance entities that do not have non-deleted media objects because of join. If you want it to also return objects with empty media collection change join to leftJoin

Provide request header for Microsoft.Scheduler/jobCollections/jobs

I want to know how to provide from my Azure WebApp the user/password to provide header for my webjob
{
"name": "[concat('TraitementTableAzure-', parameters('HeliosEnvironnementName'), '-js')]",
"type": "jobs",
"apiVersion": "2016-03-01",
"location": "[resourceGroup().location]",
"properties": {
"action": {
"request": {
"method": "Post",
"uri": "[concat('https://', parameters('AzureWebAppWebJobs'), '.scm.azurewebsites.net/api/triggeredwebjobs/', parameters('HeliosEnvironnementName'), '_TraitementTableAzure/run')]",
"headers": {
"authorization": "[concat('Basic ', reference('???').???)]" }
},
"type": "Http",
"retryPolicy": {
"retryType": "Fixed"
}
},
"startTime": "[parameters('SchedulesStartTime').SchedulerTraitementTableAzureStartTime]",
"recurrence": {
"frequency": "Day",
"interval": 1
},
"state": "Enabled"
},
"dependsOn": [
"[resourceId('Microsoft.Scheduler/jobCollections', variables('AzureSchedulerName'))]"
],
"tags": {
"displayName": "Cedule_TraitementTableAzure"
}
},
I found information over Azure Portal but not in ARM Template under webjob Properties. How can reference information on the blue arrow over my ARM template ?
How can reference information on the blue arrow over my ARM template ?
If we want to get the publishingPassword, then we could use ListPublishingCredentials API in the ARM template via list function, list(concat('Microsoft.Web/sites/', parameters('websisteName') ,'/config/publishingcredentials'), '2016-08-01').properties.publishingPassword
According to your template, it seems the that you want to call WebJob REST API, If it is that case, the authorization header is base64(publishusername:publishpassword).
base64(concat(list(concat('Microsoft.Web/sites/', parameters('websisteName'),'/config/publishingcredentials'), '2016-08-01').properties.publishingUserName,':',list(concat('Microsoft.Web/sites/', parameters('websisteName') ,'/config/publishingcredentials'), '2016-08-01').properties.publishingPassword))
I write a demo to test it on my side, it works correctly .
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"websisteName": {
"type": "string"
}
},
"resources": [],
"outputs": {
"base64Output": {
"type": "string",
"value": "[base64(concat(list(concat('Microsoft.Web/sites/', parameters('websisteName'),'/config/publishingcredentials'), '2016-08-01').properties.publishingUserName,':',list(concat('Microsoft.Web/sites/', parameters('websisteName') ,'/config/publishingcredentials'), '2016-08-01').properties.publishingPassword))]"
}
}
}

How to Query Google Cloud Datastore for array

I have wriiten the query to get the all the list of Event Data entities. The result is Coming like this from the google Data Store.
[{
"key": {
"id": 5678669024460800,
"kind": "Event",
"path": [
"Event",
5678669024460800
]
},
"data": {
"createdAt": "2017-03-27T06:28:58.000Z",
"users":["test1#xxx.com","test2#xxx.com","test3#xxx.com"]
}
},
{
"key": {
"id": 5678669024460800,
"kind": "Event",
"path": [
"Event",
5678669024460800
]
},
"data": {
"createdAt": "2017-03-27T06:28:58.000Z",
"users":["test1#xxx.com"]
}
},
{
"key": {
"id": 5678669024460800,
"kind": "Event",
"path": [
"Event",
5678669024460800
]
},
"data": {
"createdAt": "2017-03-27T06:28:58.000Z",
"users":["test2#xxx.com","test3#xxx.com"]
}
}]
but i need to Write a Query to filter by Email'id. means i need to fetch the entities which are match with the Email id. For Eg if i pass the emailid as "test1#xxx.com" i should get final Result like this. Can anybody help me on this.
[{
"key": {
"id": 5678669024460800,
"kind": "Event",
"path": [
"Event",
5678669024460800
]
},
"data": {
"createdAt": "2017-03-27T06:28:58.000Z",
"users":["test1#xxx.com","test2#xxx.com","test3#xxx.com"]
}
},
{
"key": {
"id": 5678669024460800,
"kind": "Event",
"path": [
"Event",
5678669024460800
]
},
"data": {
"createdAt": "2017-03-27T06:28:58.000Z",
"users":["test1#xxx.com"]
}
}]
The GQL query would be something like -
SELECT * FROM Event WHERE users='test1#xxx.com'
You need to make sure the users property is indexed in order for the search to work, otherwise you may not get any results back.

Resources