laravel - change value in array for API Resources - laravel

{
"data": {
"username": "candy",
"certificates": [
{
"id": 11,
"category_id": 1,
"certname": "cert name test",
"created_at": "2018-08-18 00:58:12",
"updated_at": "2018-08-18 00:58:12"
}
]
}
}
Above is a response by using Eloquent: API Resources.
I would like to put category name instead of category_id.
Below is resource class
public function toArray($request)
{
return [
'nickname' => $this->nickname,
'certificates' => $this->certificates,
];
}
certificates are in array (hasMany relationship)
certificates belongsTo category

In this case, in the resource class you can fetch category name for each certificate and attach it.
public function toArray($request)
{
$certificateList = $this->certificates;
foreach($certificateList as $ceritificate) {
// fetch only the category name from the database.
// attach to the certificate.
$categoryName = Category::where('id', $certificate->category_id)->pluck('name')->first();
$certificate->setAttribute('category_name, $categoryName);
}
// then as usual
return [
'nick_name' => $this->nick_name,
'certificates' => $certificateList
];
}

This Might Help,
Run a foreach loop
$category = "Your SELECT Query";
foreach ($category as $value) {
$categoryId = json_decode($value->category_id);
$x = Category::select('certname')->whereIn('id', $categoryId)->get();
foreach ($x as $as) {
$y[] = $as->certname;
}
$value->certname = $y;

you can just do it like this
in controler
return CertificateResource::collection(Certificate::with('category')->get());
in CertificateResource
return [
'nickname' => $this->nickname,
'certificates' => $this->certificates,
'category_name'=>$this->whenLoaded('category', function () {
return $this->category->category_name;
}),
];

Related

spatie/laravel-medialibrary, filters on getMedia() function not working

I am trying to get media for certain modal as follows:
public function show(Gallery $gallery)
{
$images = $gallery->getMedia('default'); //returns images
// $images = $gallery->getMedia('default', ['name', 'original_url']); //returns empty
return response()->json(['data' => $images]);
}
when not adding filters I get the correct data as follows:
{
"data": {
"686cc1b1-cfdc-425d-9b93-c99290f0d35e": {
"name": "Screenshot from 2022-06-27 23-29-29",
"file_name": "Screenshot-from-2022-06-27-23-29-29.png",
"uuid": "686cc1b1-cfdc-425d-9b93-c99290f0d35e",
"preview_url": "",
"original_url": "http://app.test/storage/media/25/Screenshot-from-2022-06-27-23-29-29.png",
"order": 1,
"custom_properties": [],
"extension": "png",
"size": 10546
}
}
}
but when I use filters I get empty array.
You have to retrieve single media, then you can chain property name
$gallery->getMedia('default')[0]->name;
or
$gallery->getFirstMedia('default')->name;
If you want to return json with name and original_url field for every media, that can be achieved by using API resource, something like this:
$images = $gallery->getMedia('default');
return MediaResource::collection($images);
and in MediaResource class you have:
public function toArray($request)
{
return [
'name' => $this->name,
'original_url' => $this->original_url
];
}

How to get a collection of multiple ralationships using Eloquent?

I have a table that contains foreign keys of product properties and their values.
product_id
feature_id
value_id
1
1
2
1
1
3
1
2
4
How to get a collection of that values using Eloquent?
Something like this
product => [
id => 1,
...
features => Collection: [
Feature: [
id => 1,
name => Size,
values => [
Value: [
id => 2,
name => M
],
Value: [
id: 3,
name: L
]
]
],
Feature: [
id => 2,
name => Color,
values => [
Value: [
id => 4,
name => Red
]
]
]
]
]
This is my solution.
class Product extends Model
{
protected $appends = ['features'];
protected array $features;
protected bool $featuresAppend = false;
public function getFeaturesAttribute(): Collection
{
if ($this->featuresAppend === false) {
$this->appendFeatures();
}
return collect($this->features);
}
public function productFeatures(): BelongsToMany
{
return $this->belongsToMany(Feature::class, 'product_features');
}
public function productFeatureValues(): BelongsToMany
{
return $this->belongsToMany(
FeatureValue::class,
'product_features',
'product_id',
'value_id'
);
}
protected function appendFeatures(): void
{
// Get futures and values by relationships
$features = $this->productFeatures()->get()->keyBy('id');
$values = $this->productFeatureValues()->get()->keyBy('id');
// Create features-values structure
$features->each(
function ($f) {
$this->features[$f->id] = new \StdClass();
$this->features[$f->id]->feature = $f;
}
);
// Appends values to future
$values->each(
function ($v) {
if (array_key_exists($v->feature_id, $this->features)) {
$this->features[$v->feature_id]->values[$v->id] = $v;
}
}
);
$this->featuresAppend = true;
}
}
I'm looking for a better solution to this problem or a solution using native Laravel features.

Laravel - How to consume and refresh external api into db using Guzzle

I am having this model in my Laravel-5.8 project:
Employee
class Employee extends Model
{
protected $table = 'employees';
protected $primaryKey = 'id';
protected $fillable = [
'staff_code',
'first_name',
'last_name',
'department_id',
];
public function department()
{
return $this->belongsTo('App\Department','department_id');
}
}
That is,:
App\Employee
Also I have an external api that comes in form of JSON get request.
https://api.employees.net/allemployees
I have viewed it with postman get request and I have something like this:
{
"ID": "1",
"StaffCode": "STC001",
"FirstName": "Japheth",
"LastName": "Shalom",
"DepartmentCode": "dep2",
},
{
"ID": "2",
"StaffCode": "STC002",
"FirstName": "Ahitophel",
"last_name": "Nedum",
"DepartmentCode": "dep1",
},
{
"ID": "3",
"StaffCode": "STC003",
"FirstName": "Joash",
"FirstName": "Nathan",
"DepartmentCode": "dep2",
},
and so on... this continues
Already I have created this function:
use App\Employee;
use App\Department;
public function index()
{
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res, true);
...
}
Apart from the id and staff_code that are UNIQUE, any of the others fields too can change from the source.
Since any of the fields can change at any time. How do I refresh the entire db, save new data and update changes?
Thank you
I could do something like this:
use App\Employee;
use App\Department;
public function index()
{
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res->getBody()->getContents(), true);
foreach($clientdatas as $clientdata)
{
$employee = Employee::firstOrNew(['id' => $clientdata['ID']]);
$employee->staff_code = $clientdata['StaffCode'];
$employee->first_name = $clientdata['FirstName'];
$employee->last_name = $clientdata['LastName'];
$employee->save();
}
}
Every time you will make an API call, create an instance of the employee model, or get the associated model if the ID exists. Then assign the new values and save your model. This way, you will be able to either create or update the models in a single loop without any complexities.
Don't know will it work or not but the logic you can keep.. In the other answer he is querying under a loop which is bad!
Hope It will Help you a little bit
public function index() {
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res->getBody()->getContents(), true);
// create a blank array for insert
$insert_arr = [];
foreach($clientdatas as $clientdata) {
$make_array = [
'id' => $clientdata['ID'],
'staff_code' => $clientdata['StaffCode'],
'first_name' => $clientdata['FirstName'],
.
.
];
array_push($insert_arr, $make_array);
// Now the the $insert_arr will ready for insert
}
// Here you have to check its duplicate or not
$exist_in_db = Employee::all('id')->toArray(); // get the id array from db
// do the stuff for unset the duplicate
$final_id = array_map(function($value) {
return $value['id'];
}, $team_id);
unset($exist_in_db);
if(count($final_id) > 0){
foreach ($insert_arr as $key => $value) {
if (in_array($value['id'], $final_id)) {
unset($insert_arr[$key]);
} else {
array_push($final_id, $value['id']);
}
}
}
// finally insert it here
if (count($insert_arr) > 0) {
Employee::insert($insert_arr);
}
}
Let me know its helpful or not!

Laravel API : how to get only some fields and sort the response

I would like to know if I do the things correctly.
Let's say I have a table "countries". To get only some fields of this table, in a certain order, I have this url :
/countries?fields=id,country_name&desc=country_name
And the result is clear:
[
{
"id": "SP",
"country_name": "Spain"
},
{
"id": "IT",
"country_name": "Italy"
},
{
"id": "FR",
"country_name": "France"
},
{
"id": "CN",
"country_name": "China"
} ]
To do that I have this route :
Route::get('/countries', 'CountryController#index');
And the method index is :
public function index(Request $request)
{
$query = Country::query();
if ($request->has('fields')){
$fields = explode(',', $request->input('fields') );
foreach ($fields as $field) {
$query->addSelect($field);
}
}
if ($request->has('sort')){
$query->orderBy($request->input('sort'));
}
if ($request->has('desc')){
$query->orderBy($request->input('desc'), 'desc');
}
$countries = $query->get();
return response()->json($countries, 200);
}
It works fine.
My question is am I doing the things correctly ? Is there any other methods ?
To prevent unknown column exception try this:
import Schema class use Illuminate\Support\Facades\Schema;
add this:
$table = "countries";
if ($request->has('fields')){
$fields = explode(',', $request->input('fields') );
foreach ($fields as $field) {
if(!Schema::hasColumn($table,$field)){
return response("Unknown field", 422);
}
$query->addSelect($field);
}
}
What you are doing to me has no vulnerability in it and is very optimized too.
You can try using this:
$countries = $query->pluck('id', 'country_name');
Please check and let me know.

laravel resource collection has blank output

I am trying to get a json output of a collection but all I am getting is a data [].
I have 2 tables.
TABLE:Player ||
id |
name
and
TABLE:FlightTime || id | vehicle | totaltime | player_id (foreign key)
I am trying to get all the flighttime entry for a particular player as a collection.
My FlightTime resource:
class FlightTime extends JsonResource
{
public function toArray($request)
{
return [
'vehicle' => $this->vehicle,
'total-time' => $this->totaltime,
];
}
}
And my FlightTimeCollection:
class FlightTimeCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'data' => $this->collection,
'test' => 'did this work',
];
}
}
My api route is set as
Route::get('/v1/player/{name}/flights', 'PlayerController#showFlightbyName');
And I have this in my controller:
public function showFlightbyName($name)
{
$pid = Player::select('id')->where('name', $name)->first();
return new FlightTimeCollection(FlightTime::where('player_id', $pid)->get());
}
Now when I visit localhost/api/v1/player/Angel/flights, No error is thrown. But all I am getting is this.
{
"data": [],
"test": "did this work"
}
I just can't figure out what's going on here and what I did wrong.
You should treat the toArray() method in your FliightTimeCollection the same way you treat it in FlightTimeResource. The collection will be automatically wrapped in data => [stuff]'.
So, like this:
class FlightTimeCollection extends ResourceCollection
{
public function toArray($request)
{
return [
'vehicle' => $this->vehicle,
'another_field' => $this->field2,
// ...
];
}
}
Result of that would be
{
"data": [
{"vehicle": "some value", "another_field": "some value"},
// ...
],
}
I got it working. $pid is an obj and I needed to get the value out of $pid->id
public function showFlightbyName($name)
{
$pid = Player::select('id')->where('name', $name)->first();
return new FlightTimeCollection(FlightTime::where('player_id', $pid->id)->get());
}

Resources