Laravel resource ignoring given fields - laravel

I'm trying to convert a given API response in something easy to work with.
This is what I have so far:
Controller:
public function drive()
{
$optParams = [
'corpora' => 'drive',
'driveId' => env('GOOGLE_DRIVE_ID'),
'includeItemsFromAllDrives' => true,
'supportsAllDrives' => true,
'fields' => 'files(*)'
];
$results = $this->googleDrive->files->listFiles($optParams);
$data = collect($results);
$collection = new FileCollection($data);
dd($collection);
return 'Hi!';
}
FileCollection resource:
public function toArray($request)
{
return [
'data' => $this->collection,
'meta' => ['files_count' => $this->collection->count()],
];
}
File resource:
public function toArray($request)
{
return [
'name' => $this->resource['name'],
'mime' => $this->resource['mimeType'],
'parents' => $this->resource['parents'],
'version' => $this->resource['version'],
'webDownloadLink' => $this->resource['webContentLink'],
'webLink' => $this->resource['webViewLink'],
'modified_at' => $this->resource['modifiedTime'],
'size' => $this->resource['size']
];
}
This is the result I'm getting:
FileCollection {#223 ▼
+collects: null
+collection: Collection {#243 ▶}
+resource: Collection {#243 ▼
#items: array:2 [▼
0 => File {#224 ▼
+resource: Google_Service_Drive_DriveFile {#279 ▶}
+with: []
+additional: []
}
1 => File {#263 ▼
+resource: Google_Service_Drive_DriveFile {#269 ▶}
+with: []
+additional: []
}
]
}
+with: []
+additional: []
}
So as you can see the types of resources are correct, but for some reason the 'meta' in the FileCollection isn't there, nor are the fields in the File resource. All fields are still shown, like 30+ (instead of the 8 requested in the FileResource).
Am I missing something here?
EDIT:
When accessing the collection with the toArray() method ($collection->toArray(null)), I do indeed get the appropriate result:
array:2 [▼
"data" => Collection {#243 ▼
#items: array:2 [▼
0 => File {#224 ▶}
1 => File {#263 ▶}
]
}
"meta" => array:1 [▼
"files_count" => 2
]
]
So how do I make sure now that this collection uses the toArray() of the FileResources? (I'm still getting over 30 fields, instead of 8).
PS: I don't really get why I need to call the toArray(), nowhere in their documentation is it written : https://laravel.com/docs/5.8/eloquent-resources .

Related

Retrieving data from a countries API

I'm using an API to get a list of countries in Laravel. I have been able to isolate the countries list only but the countries now have an inner array with details of the country. I only need the name. I've tried using foreach but it didn't work.
This below is the result from the api
#items: array:2 [▼
"countries" => array:198 [▼
0 => array:4 [▼
"code" => "BT"
"name" => "Bhutan"
"geonameid" => 1252634
"depends_on" => null
]
1 => array:4 [▶]
This below is the code fetching it
$response = Http::withHeaders([
'x-rapidapi-host' => 'world-geo-data.p.rapidapi.com',
'x-rapidapi-key' => '1fa601995fmshcc1d2fcc97ee24cp1ac29djsn9b9b11cc10ec',
//'x-rapidapi-key' => config('app.rapid_api_key'),
])->get('https://world-geo-data.p.rapidapi.com/countries');
//dd($response->collect());
return $response->collect()->pluck('name')
->all();
I'm trying to get only the name value. the return is returning null
I think this is what you want:
return collect($response->collect()["countries"])->pluck('name');
The result will be like:

I want to sort the related values that are obtained by contain in pagination (CakePHP4)

Get the value of contain for the Slugs associated with the Posts model.
I want to sort them in order of the ID of the retrieved Slugs table.
in PostsController
/**
* Index method
*
* #return \Cake\Http\Response|null|void Renders view
*/
public function index()
{
$this->paginate = [
'limit' => 10,
'contain' => ['Slugs'],
'order' => [
'Slugs.id' => 'desc',
],
];
$posts = $this->paginate($this->Posts);
$this->set(compact('posts'));
}
The retrieved values will be displayed in order of decreasing ID (asc).
ID in descending order.
Check the contents of the $posts value in dd($posts).
0 => App\Model\Entity\Posts {#163 ▼
#_accessible: array:6 [▶]
#_fields: array:6 [▶]
// ....
id: 1
title: "CakePHP"
user_id: 1
created: Cake\I18n\FrozenTime #1613560300 {#164 ▶}
modified: Cake\I18n\FrozenTime #1613560300 {#195 ▶}
users: array:2 [▼
0 => App\Model\Entity\Slug {#213 ▼
// ...
id: 1
name: "PHP7.2"
[new]: false
// ...
}
1 => App\Model\Entity\Slug {#224 ▼
id: 2
name: "CakePHP4"
// ...
I have tried the following
'order' => [
'Posts.Slugs.id' => 'desc',
],
or
$posts = $this->paginate($this->Posts->find()->order(['Slugs.id']);
How can I get the best results?
So a Post has many Slugs, and when you load posts in the pagination (sorted by some field in the post), you want the slugs in those posts to be ordered by id? You should be able to do this with the queryBuilder parameter in the containment:
$this->paginate = [
'limit' => 10,
'contain' => [
'Slugs' => [
'queryBuilder' => function (Query $q) {
return $q->order(['Slugs.id']);
}
],
],
];

Laravel parameterBag as array issues when inserting

I am trying to insert mass data but i get this error when i iterate through the request:
Symfony\Component\Debug\Exception\FatalThrowableError Cannot use
object of type Symfony\Component\HttpFoundation\ParameterBag as array
Request example:
request: Symfony\Component\HttpFoundation\ParameterBag {#52 ▼
#parameters: array:4 [▼
"_token" => "Z1sF2K5LHU1bsQ4l3JRaOLCTQDmJ47qakigmrfI5"
"name" => "Rousaddasd 1"
"secsaddsans" => array:1 [▼
"secsdfs1" => array:2 [▼
"name" => "Sectdfs 1"
]
]
"submit" => "Submit"
]
}
Loop to go through the request and insert:
$abc = new abc;
$abc->create(['user_id' => 1, 'name' => $request->name, 'description' => 'test description']);
foreach($request as $item){
$asd = new asd;
$asd->name = $item['name'];
$asd->description = 'test description';
$abc->asds()->create([$asd]);
}
Im adding some data "inline" because i didnt handle them in the form yet, thats why the added duration and duration_unit for example.
You can use $request as array like this:
$request = $request->all();
And loop like:
foreach($request['sections'] as $item) {
....
foreach($item['exercises'] as $item2) {
....
}
}

How to get the common values from 2 Laravel collections

I have 2 Collections in Laravel, and I want only common values in my $result object. I see that $collection->intersect() works only for 1D array.
Below are the collections
Collection {#1086 ▼
#items: array:5 [▼
0 => {#1115 ▼
+"name": "Light"
+"class": "ABC"
+"id": 4
}
1 => {#1113 ▼
+"name": "Milo"
+"class": "XYZ"
+"id": 10
}
2 => {#1120 ▼
+"name": "Milo Test"
+"class": "ABC"
+"id": 12
}
3 => {#1102 ▼
+"name": "KMSMiloCow"
+"class": "ABC"
+"id": 16
}
4 => {#1106 ▼
+"name": "MiloCows"
+"class": "XYZ"
+"id": 18
}
]
}
Collection {#1086 ▼
#items: array:5 [▼
0 => {#1115 ▼
+"name": "Light"
+"class_name": "ABC"
+"id": 4
}
]
}
Now in my result, I just need this
Collection {#1086 ▼
#items: array:5 [▼
0 => {#1115 ▼
+"name": "Light"
+"class": "ABC"
+"id": 4
}
]
}
I have no idea this would help you or not but these will be useful
$common_collection = $collection_1->whereIn('id', $collection_2->pluck('id')->toArray())
->unique('id')
->sortBy('id');
To get a collection with common elements, you can use filter():
The filter method filters the collection using the given callback, keeping only those items that pass a given truth test
$commonCollection = $collection1->filter(function ($value, $key) use ($collection2){
return $collection2->contains($value);
});
I think using collection method each and contains, it can be done like this
$collection1->each(function ($value, $key) use ($collection2){
return $collection2->contains($value);
});
dd($collection1);
I test it in routes file web.php like
use Illuminate\Support\Collection;
Route::get('test', function(){
$collection1 = new Collection([
'bear',
'whale',
'chicken',
'tardigrade'
], [[
'bear8',
'whale44',
'chicken45',
'tardigrade445'
]]);
$collection2 = new Collection([
'bear1',
'whale2',
'chicken3',
'tardigrade4'
], [[
'bear',
'whale',
'chicken',
'tardigrade'
]]);
$collection1->each(function ($value, $key) use ($collection2){
return $collection2->contains($value);
});
dd($collection1);
});
use intersect https://laravel.com/docs/9.x/collections#method-intersect
for example:
$commonValues = $collection1->pluck("id")->intersect($collection2->pluck("id"));
dd($commonValues);
Then get common collections
dd($collection1->whereIn("id", $commonValues));
try this
$a1 = array(
array('name' => 'asdfjkl;', 'class' => 'foo'),
array('name' => 'qwerty', 'class' => 'bar'),
array('name' => 'uiop', 'class' => 'baz'),
);
$a2 = array(
array('name' => 'asdfjklk;', 'class' => 'foo'),
array('name' => 'qwertyxs', 'class' => 'bar'),
array('name' => 'uiop', 'class' => 'baz'),
);
$cc = array_uintersect($a1, $a2, 'cmp');
print_r($cc);
function cmp($a1, $a2){
return strcasecmp($a1['name'] , $a2['name']);
}

Get relation of relation

I'm trying to get the comments of the links with laravel relationship, the comments of links return normally, but I don't know how to get it in view or dd(), how can I do it?
Controller:
$page = Page::where('friendly_url', $id)
->select('id', 'photo', 'friendly_url', 'name', 'description', 'followers', 'links', 'tag_id', 'links_clicks')
->with('ptag', 'links', 'links.comments', 'links.tag')
->with(['links.comments.user' => function($query) {
$query->select('id', 'name', 'lastname');
}])->with(['links.comments.userProfile' => function($query) {
$query->select('id', 'photo');
}])->first();
dd($page->getRelation('links')
Collection {#301 ▼
#items: array:2 [▼
0 => Link {#307 ▼
#relations: array:2 [▼
"comments" => Collection {#316 ▼
#items: array:1 [▶]
"tag" => Tag {#322 ▶}
]
dd($page->getRelation('links')->getRelation('comments'))
BadMethodCallException
Method getRelation does not exist.
dd($page->getRelation('links')->comments)
Exception
Property [comments] does not exist on this collection instance.
EDIT:
I want to show the attributes of comment and comment.user, how I can do it?
foreach($page->getRelation('links')->pluck('comments') as $comment) {
dd($comment);
}
Collection {#327 ▼
#items: array:1 [▼
0 => Comment {#325 ▼
#attributes: array:5 [▼
"id" => 3
"content" => "teste"
"link_id" => 1
"user_id" => 1
"created_at" => "2018-01-11 00:47:32"
]
#relations: array:2 [▼
"user" => User {#330 ▼
#attributes: array:3 [▼
"id" => 1
"name" => "Halysson"
"lastname" => "Teves dos Santos"
]
}
"userProfile" => UserProfile {#326 ▶}
]
Try this-
foreach($page->links as $link){
$comments = $link->comments;
}
You should define relations first on relevent models and then using 'with' function can load models with relations OR a relation can be called directly by single model see documentation for further details
eg: you have defined a relation for user to phone, as user has a phone, one to one relation. in user model define a relation like
public function phone()
{
return $this->hasOne('App\Phone');
}
now to call this relation on user model instance.
$user = User::find(1);
dd($user->phone);
Because you're using the select() method, you also need to include all the foreign keys in it to allow Eloquent to be able to load these relationships.
But since you just start using Laravel, I'd recommend you to just remove select() method from this complex query.
If you want the links of a page :
$page->links
if you want all the comments of a page :
$page->links->pluck('comments')
that's it :)

Resources