На данной странице представлен список интересных возможностей по примерам.
Если объявить аннотацию фильтрации:

то получаем возможность фильтровать данные через связанные сущности (любой вложенности по связям):

Нюанс 1
можно не указывать id в конце свойства для фильтрации:
* @ApiFilter(SearchFilter::class, properties={
* "products.offerProducts.offer": "exact"
* })но тогда в запросе тоже писать id не нужно (правильный пример):
curl --insecure -X GET "https://localhost/api/categories?products.offerProducts.offer=22&page=1&itemsPerPage=30" -H "accept: application/json"важно: имейте ввиду, что если в анотации не пишите id, а в запросе пишите, то фильтрация не сработает и вернутся неотфильтрованные данные.
Нюанс 2
возвращается всегда уникальный список категорий (неважно сколько продуктов участвует в связях products.offerProducts )
Нюанс 3
когда используют SearchFilter без указания полей, включается фильтрация по всем полям сущности, но если указать какое-либо поле (как в примере выше), то фильтрация по всем полям выключается (доступна только фильтрация по указанным полям).
Если объявить аннотацию сортировки:

то получим возможность сортировать данные:

результат сортировки соответствует ожиданию (обратите внимание на поле parentId в результате).
Нюанс
порядок указания полей сортировки влияет на результат (сначала сортируем по parentId, потом по id):
curl --insecure -X GET "https://localhost/api/categories?order%5BparentId%5D=desc&order%5Bid%5D=desc&page=1&itemsPerPage=30" -H "accept: application/json"таким образом будет выполнен SQL: ORDER BY parentId DESC, id DESC
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
/**
* @ApiResource(
* @ApiFilter(PropertyFilter::class)
*/
class CheeseListingзапрос:
?properties[]=title&properties[]=shortDescriptionРассмотрим несколько примеров взаимодействия разных сущностей.
Создание группы и сайта одновременно:
curl -X POST "http://any.local:8888/api/site_groups" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d "{\"name\":\"group 0\",\"sites\":[{\"name\":\"site 0\"}]}"
201 Response body
{
"@context": "/api/contexts/SiteGroup",
"@id": "/api/site_groups/27",
"@type": "SiteGroup",
"name": "group 0",
"sites": [
{
"@id": "/api/sites/23",
"@type": "Site",
"name": "site 0",
"id": 23,
"siteGroupId": 27,
"siteGroupName": "group 0"
}
],
"id": 27
}Создание группы и сайта одновременно (повторно):
curl -X POST "http://any.local:8888/api/site_groups" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d '{"name":"group 0","sites":[{"name":"site 0", "domain": "site.ru"}]}'
409 Response body
{
"title": "The object already exist"
}Создание группы с ранее созданным сайтом:
curl -X POST "http://any.local:8888/api/site_groups" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d '{"name":"group 1","sites":["/api/sites/2"]}'
201 Response body
{
"@context": "/api/contexts/SiteGroup",
"@id": "/api/site_groups/27",
"@type": "SiteGroup",
"name": "group 1",
"sites": [
{
"@id": "/api/sites/23",
"@type": "Site",
"name": "site 0",
"id": 23,
"siteGroupId": 27,
"siteGroupName": "group 0"
}
],
"id": 27
}Изменить имя группы + список сайтов входящих в данную группу:
curl -X PUT "http://any.local:8888/api/site_groups/1" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d "{\"name\":\"new group name\",\"sites\":[\"/api/sites/1\"]}"сразу 2 сайта в группе:
curl -X PUT "http://any.local:8888/api/site_groups/1" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d "{\"name\":\"new group name\",\"sites\":[\"/api/sites/1\",\"/api/sites/2\"]}"Изменить имя группы + удалить все сайты из группы:
curl -X PUT "http://any.local:8888/api/site_groups/1" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d "{\"name\":\"string\",\"sites\":[]}"Создать Попап+добавить к нему группу конфигурации:
curl -X POST "http://any.local:8888/api/popup_windows" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d "{\"name\":\"string\",\"html\":\"\",\"javascript\":\"string\",\"settings\":\"string\",\"actionConfigurations\":[\"/api/action_configurations/1\"]}"
curl -X POST "http://any.local:8888/api/popup_windows" -H "accept: application/ld+json" -H "Content-Type: application/ld+json" \
-d '{"name":"group 1","sites":["/api/sites/2"]}'Редактирование существующего события:
curl -i 'http://any.local:8888/api/action_configurations/2' -X PUT -H 'accept: application/json, text/plain, */*' -H 'content-type: application/json' \
--data-binary '{"name":"Yapro.ru"}' -H 'X-ECOM-DEBUG: true'Удаление popup_window:
curl -X DELETE "http://any.local:8888/api/popup_windows/11" -H "accept: */*"
204 ResponseПагинация от клиента:
curl 'http://localhost:8888/api/popup_windows?page=1&pagination=true&itemsPerPage=20'api_platform.eager_loading = true заставляет \ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\EagerLoadingExtension использовать sql-join'ы для получения данных всех связанных сущностей, при этом вложенность никак ограничить нельзя (все что связано, все будет вытащено из бд).
Уменьшить вложенность данных в ответе можно только с помощью аннотаций групп симфони-сериализатора. У себя в проекте мы решили не указывать группу нормализации для свойств-отношений (свойств коллекций в сущности) которые имеют очень большую вложенность, т.е. меняем это:
/**
* @Groups({"apiRead", "apiWrite"})
*/
private Collection $mainProducts;на это:
/**
* @Groups({"apiWrite"})
*/
private Collection $mainProducts;Т.е. отношения запрашивать будем из самой коллекции, например: "/api/bundle_main_products" c фильтром по свойству bundle.
Но, если потребуется все-таки получать сразу коллекцию, то укажем группу "Bundle:apiRead" для свойств, на необходимую глубину отношений.
Если вдруг (непонятно зачем) появится такая необходимость, то сделать это можно так:
/**
* @Route(path="/admin/api/v1")
*/
class TemplatesController extends AbstractController
{
/**
* @Route(
* name="get_template",
* path="/templates/{id}",
* methods={"GET"},
* defaults={
* "_api_resource_class": Template::class,
* "_api_item_operation_name": "get_template"
* },
* requirements={"id": "\d+"}
* )
*
* @return JsonResponse
*/
public function getTemplateAction(Template $data)
{
return new JsonResponse($this->templateTransformer->transformFull($data));
}Как сделать запрос с частичной выборкой данных
Например:
К сожалению, из коробки такого функционала нет, но его можно реализовать с помощью дата-провайдера.
@SerializedName("site_group_id")
@ApiSubresource(maxDepth=1)
@ApiProperty(attributes={"fetchEager": false, "fetchable": false})Сравним два API-подхода выполнения запросов из браузера.
fetch("http://95.165.102.48:8888/login",
{
"credentials": "include",
"headers": {
"accept":"application/json, text/plain, */*",
"content-type": "application/json"
},
"referrer": "http://localhost:4200/login",
"referrerPolicy": "no-referrer-when-downgrade",
"body": "{\"email\":\"igor@fox.pro\",\"password\":\"igor@fox.pro\"}",
"method": "POST",
"mode": "cors"
}
);с помощью JavaScript (вариант 1):
var xmlhttp = new XMLHttpRequest();
xmlhttp.withCredentials = true;
xmlhttp.open("POST", "http://localhost:4200/login");
xmlhttp.setRequestHeader("Accept", "application/json");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify({email:"igor@fox.pro", password:"igor@fox.pro"}))с помощью JavaScript (вариант 2):
var jbody = {
"name": "Просто значение",
"visitorType": 0
};
var xmlhttp = new XMLHttpRequest();
xmlhttp.withCredentials = true;
xmlhttp.open("POST", "http://any.local:8888/api/action_configurations");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(jbody));На этом все, всем удачки.
p.s. create multiple resources
Комментарии
Комментариев пока нет.