Я работал над созданием чистого интерфейса для нашего различного веб-приложения и столкнулся с трудностями, связанными с API-ресурсами Laravel, которые неправильно преобразовывают входящий массив json в коллекции laravel.
Я могу сделать это с одним ресурсом:
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
use App\Product;
class ProductResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'name' => $this->resource['product']['name'],
'description' => $this->resource['product']['description'],
'price' => $this->resource['product']['rental_rate']['price']
];
//return parent::toArray($request);
}
}
распечатать этот ответ:
{"name":"Arri Skypanel S60-C","description":"Arri Sky Panel S60-C 450w input with a 2000w tungsten equivalent & Combo Stand","price":"260.0"}
Однако попытка взять этот единственный предмет и превратить его в набор предметов никуда не денется.
Кто-нибудь понял, что мне не хватает?
Извлечение данных API выглядит следующим образом:
namespace App;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Client;
class ThirPartyAPI
{
private $url = 'https://api.third-party.com/api/v1/';
public function pull($query, $additionalParams) {
$client = new Client;
$result = $client->get($this->url . $query . $additionalParams, [
'headers' => [
'Content-Type' => 'application/json',
'X-AUTH-TOKEN' => env('CURRENT-AUTH-TOKEN'),
'X-SUBDOMAIN' => env('CURRENT-SUBDOMAIN')
]
]);
$array = json_decode($result->getBody()->getContents(), true);
return $array;
}
}
API возвращает много данных JSON.
Это модель продукта:
public function getAllProducts() {
try {
$productData = [];
$query = "/products?page=1&per_page=3&filtermode=active";
$additionalParams = "";
$productData = new ThirdPartyAPI;
$productData = $productData->pull($query, $additionalParams);
$productData = $productData['products'];
return ProductsResource::make($productData);
} catch (\Exception $ex) {
return $ex;
} catch (\Throwable $ex) {
return $ex;
}
}
Прямо сейчас я пытаюсь что-то сделать, чтобы преобразовать все возвращенные массивы во что-то, что я могу контролировать больше:
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\Resource;
class ProductsResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'products' => $this->collection->mapInto(function($request) {
return[ 'name' => $this->resource['name'],
'description' => $this->resource['description'],
'price' => $this->resource['rental_rate']['price']
];
})
];
}
Однако var_dumping данные просто возвращают это:
object(App\Http\Resources\ProductsResource)[200]
public 'resource' =>
array (size=3)
0 =>
array (size=37)
'id' => int 164
'name' => string '10A Dimmer' (length=10)
[Lots of data]
...
'sale_rates' =>
array (size=0)
...
1 => .....
[cont]
public 'with' =>
array (size=0)
empty
public 'additional' =>
array (size=0)
empty
Я пробовал различные формы преобразования данных в возвращаемой информации json, и у меня не было много результатов, кроме ошибок и запутанного бизнеса. Я немного сомневаюсь в том, как Laravel обрабатывает обработку ресурсов API.
Итак, после некоторого изучения методов Laravel ‘make’, ‘mapinto’ и ‘map’ для коллекций, я в итоге получил рабочий результат этого преобразования здесь:
$productData = ThirdPartyAPI;
$productData = $productData->pull($query, $additionalParams);
$productData = $productData['products'];
$products = collect($productData)->map(function($row){
return ProductsResource::make($row)->resolve();
});
var_dump($products);
Это var_dump возвращает это:
object(Illuminate\Support\Collection)[228]
protected 'items' =>
array (size=3)
0 =>
array (size=3)
'name' => string '10A Dimmer' (length=10)
'description' => string '10amp Dimmer (Max 2.4k)' (length=23)
'price' => string '5.0' (length=3)
....
[And so on]
Исходная информация, которая была возвращена, была многомерным массивом.
$returnedArray = array(
['array' => 1, 'name' => 'name', etc],
['array' => 2, 'name' => 'name, etc]
);
Метод коллекции Laravel по умолчанию превращает только верхний массив в коллекцию. Чтобы должным образом иметь возможность контролировать результаты с помощью моделей ресурсов, мы должны преобразовать весь набор массивов в коллекции, что означает, что нам нужно перебирать возвращаемые данные, чтобы преобразовать их во что-то, что laravel может правильно прочитать. Это то, что делает метод карты.
Согласно документы it, ‘метод map выполняет итерацию по коллекции и передает каждое значение заданному обратному вызову. Функция обратного вызова может свободно изменять элемент и возвращать его, формируя новую коллекцию измененных элементов.
Метод make создает новый экземпляр коллекции. Я не знаю, что делает функция разрешения, за исключением того, что документы отметим, что он «разрешает данный класс или имя интерфейса в своем экземпляре с использованием сервисного контейнера». Я собираюсь предположить, что это означает, что он гарантирует, что проходит через класс правильно?
В любом случае, я надеюсь, что это поможет людям в будущем.
Других решений пока нет …