how to show pagination links in resource laravel - php

I have a resource in this resource I have collection , now I want to show the pagination links of that collection, how can I do it?
This is my resource
public function toArray($request)
{
return [
"name" => $this->name ,
"slug" => $this->slug ,
"bg_image" => imageGenerate("sections" , $this->bg_image) ,
"bg_color" => $this->bg_color ,
"items" => new ItemCollection($this->items()->paginate(20)) ,
];
}
this is my collection
public function toArray($request)
{
return $this->collection->map(function ($item) {
return [
"id" => $item->id ,
"name" => $item->name ,
"slug" => $item->slug ,
"image" => imageGenerate("items" , $item->image) ,
"code" => $item->code ,
"category" => $item->category->name??""
];
});
}

According to Laravel 8.x documentation, you may pass in the data that you want paginate to newly created Collection instance. Here is an example:
use App\Http\Resources\UserCollection;
use App\Models\User;
Route::get('/users', function () {
return new UserCollection(User::paginate());
});
Also see this

Related

Best way to obtain prefix and last part of url in Laravel

I have a group route like this
PHP LARAVEL 9
/**
* ACCOMODATIONS
*/
Route::controller(AccomodationsController::class)->group(function () {
Route::prefix('accomodations')->group(function () {
Route::GET('/', 'index');
Route::GET('/italy', 'index');
Route::GET('/greece', 'index');
});
});
In the controller side I want to obtain the accomodations part and the italy greece part without slashes. I'm doing like this
PHP LARAVEL 9
class AccomodationsController extends Controller
{
public function index(request $request){
$listType = [
'type' => trim($request->route()->getPrefix(), '/'),
'route' => request()->segment(count(request()->segments()))
];
dd($listType);
);
}
/*
http://example.com/accomodations outputs
array [
"type" => "accomodations"
"route" => ""
]
/*
/*
http://example.com/accomodations/italy outputs
array [
"type" => "accomodations"
"route" => "italy"
]
*/
/*
http://example.com/accomodations/greece outputs
array [
"type" => "accomodations"
"route" => "greece"
]
*/
This works but the way I'm manipulating the request in $listType seems a little bloated to me, is there a cleaner way in laravel?
Use parameterized route for same method.
Routes
Route::controller(AccomodationsController::class)->group(function () {
Route::prefix('accomodations')->group(function () {
Route::GET('/{destination}', 'index');
});
});
Controller
public function index(Request $request, $destination){
$listType = [
'type' => trim($request->route()->getPrefix(), '/'),
'route' => $destination
];
dd($listType);
);
If your destination is optional you can use optional parameter
Edit 1:
Route with Optional Parameter
Route::controller(AccomodationsController::class)->group(function () {
Route::prefix('accomodations')->group(function () {
Route::GET('/{destination?}', 'index');
});
});
Controller with Optional parameter
public function index(Request $request, $destination=''){
$listType = [
'type' => trim($request->route()->getPrefix(), '/'),
'route' => $destination
];
dd($listType);
);
you can assign any value (null, string, int, etc.) to the destination variable just like the default function argument in PHP.

Laravel resource whenLoaded hasManyTrough relation

I am trying to build a resource collection with a second resource based on a hasManyThrough relationship. When i call the actual relationship on the main resource it does provide me the correct data. Whenever i pass the data to another resource and use the whenLoaded() method, it doesn't chain the data to the main collection.
The model:
public function fields()
{
return $this->hasManyThrough(Field::class, FieldValue::class, 'component_id', 'id', 'id', 'field_id');
}
The controller:
/**
* #return JsonResponse
*/
public function index()
{
$components = Component::with(['fields'])->get();
return ComponentValueResource::collection($components)->response();
}
ComponentValueResource class:
public function toArray($request)
{
return [
'fields' => FieldResource::collection($this->whenLoaded('fields')),
];
}
FieldResource class:
public function toArray($request)
{
$fields = $this->whenLoaded('fields');
return [
'fields' => new ComponentValueResource($fields),
];
}
Output of dd(FieldResource::collection($this->whenLoaded('fields')));
#original: array:9 [
"id" => 1
"base_id" => 1
"component_id" => null
"identifier" => "text input"
"type" => "text"
"position" => 1
"created_at" => "2021-08-22 19:44:23"
"updated_at" => "2021-08-22 19:44:23"
"laravel_through_key" => 6
]
Output from the resource:
{
"data": [
{
"id": 6,
"fields": [
[]
]
},

laravel elasticsearch babenkoivan/elastic-adapter model relation

I'm looking to use elastic search on a project with model relation.
For now elastic search is working, I've followed this doc who explain how to start with this package :
elasticsearch/elasticsearch
babenkoivan/elastic-migrations
babenkoivan/elastic-adapter
babenkoivan/elastic-scout-driver
The problem is I need to able to search by relation.
this is my composant elastic migration :
Index::create('composant', function(Mapping $mapping, Settings $settings){
$mapping->text('reference');
$mapping->keyword('designation');
$mapping->join('categorie');
$settings->analysis([
'analyzer' => [
'reference' => [
'type' => 'custom',
'tokenizer' => 'whitespace'
],
'designation' => [
'type' => 'custom',
'tokenizer' => 'whitespace'
]
]
]);
});
Here my categorie elastic migration :
Index::create('categorie', function(Mapping $mapping, Settings $settings){
$mapping->keyword('nom');
$settings->analysis([
'analyzer' => [
'nom' => [
'type' => 'custom',
'tokenizer' => 'whitespace'
]
]
]);
});
My composant Model :
public function categorie()
{
return $this->belongsTo('App\Model\Categorie');
}
public function toSearchableArray()
{
return [
'reference' => $this->reference,
'designation' => $this->designation,
'categorie' => $this->categorie(),
];
}
and my categorie Model :
public function toSearchableArray()
{
return [
'nom' => $this->nom,
];
}
So if you look at the composant relation, you can see that the join mapping return the categorie relation. I dont now if I do it right but what I know is that elasticsearch didn't have any relation in the object I'm looking for.
And I didn't find any doc of how to use the join mapping method of the package.
OK, I've found the solution, the problem was in the migration you must use object in order to index the belongsToMany relationship like that
Index::create('stages', function (Mapping $mapping, Settings $settings) {
$mapping->text('intitule_stage');
$mapping->text('objectifs');
$mapping->text('contenu');
$mapping->object('mots_cles');
});
and in your model :
public function toSearchableArray()
{
return [
'intitule_stage' => $this->intitule_stage,
'objectifs' => $this->objectifs,
'contenu' => $this->contenu,
'n_stage' => $this->n_stage,
'mots_cles' => $this->motsCles()->get(),
];
}
And the result is as expected now
If you want to get "nom" of categorie, write this in composant Model instead
'categorie' => $this->categorie->nom ?? null,
$this->categorie() return the relationship, not the object.
Same problem with a belontoMany relation, and I've made the same things in order to get the relation as a nested object, but when I try to populate my index the field "mots_cles" stay empty, I don't understand why.
Here is the migration :
Index::create('stages', function (Mapping $mapping, Settings $settings) {
$mapping->text('intitule_stage');
$mapping->text('objectifs');
$mapping->text('contenu');
$mapping->nested('motsCles', [
'properties' => [
'mot_cle' => [
'type' => 'keyword',
],
],
]);
});
The model :
public function toSearchableArray()
{
return [
'intitule_stage' => $this->intitule_stage,
'objectifs' => $this->objectifs,
'contenu' => $this->contenu,
'n_stage' => $this->n_stage,
'mots_cles' => $this->motsCles(),
];
}
public function motsCles()
{
return $this->belongsToMany(MotsCle::class);
}

Laravel API Resource not returning correct value with condition

I am new to Laravel API, I want to return a book where recommended === 1
In my resources, I have this
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'about' => $this->about,
'content' => $this->content,
// 'image' => asset('/storage/'.$this->image),
'image' => $this->image_url,
// 'recommended' => $this->recommended,
'recommended' => $this->when($this->recommended === 1, $this->recommended),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'author' => $this->author,
];
I want to return books when recommended === 1
My table is Like this
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('about');
$table->string('image');
$table->string('image_url');
$table->string('epub_url');
$table->integer('author_id');
$table->string('publisher');
$table->year('year');
$table->boolean('recommended')->default(0);
$table->timestamps();
});
I was able to achieve the same thing on web using this
public function index()
{
$data = array();
$data['recommends'] = Book::where('recommended', 1)->take(10)->get();
$data['latests'] = Book::orderBy('created_at', 'desc')->take(10)->get();
return view('welcome', compact("data"));
}
But I don't know how to replicate the same using Laravel API.
UPDATE
I was able to achieve the same thing on web using this
public function index()
{
$data = array();
$data['recommends'] = Book::where('recommended', 1)->take(10)->get();
$data['latests'] = Book::orderBy('created_at', 'desc')->take(10)->get();
return view('welcome', compact("data"));
}
But I don't know how to replicate the same using Laravel API.
Normally I will get all Books or Post like this using API Resource
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'about' => $this->about,
'content' => $this->content,
'image' => $this->image_url,
'recommended' => $this->recommended,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'author' => $this->author,
];
and call it like this in my controller
public function indexapi()
{
return BookResource::collection(Book::with('author')->Paginate(16));
}
But there some cases recommended is == 1 and some recommended == 0, in this case, I want to return data only when recommended == 1
I know my question is quite confusing
Thanks.
Thanks.
If I get it right, you want to filter & get only the books with ( recommended attribute == 1 ). If thats the case you shouldn't do it in your Collection file. You should do this filtering process in your Controller before passing any data to Collection.
Here is some code example from one of my project.
In ProductController.php FILE
public function index()
{
return new ProductCollection( Product::where('recommended','1')->get() );
}
As you can see , I'm filtering the products to get only the recommended ones. Then I'm sending this filtered data to the ProductCollection. This way The collection will only return the data I want.
In ProductCollection.php FILE
public function toArray($request)
{
return [
'data' => $this->collection->map( function($data) {
return [
'id' => (integer) $data->id,
'name' => $data->name,
'category_id' => $data->category_id,
'brand_id' => $data->brand_id,
'photos' => json_decode($data->photos),
'gtin' => $data->gtin
];
})
];
}
I don't have to make any changes in Collection. Because in this way , Collection should do the job for every data it gets.

Eager Load Pivot in nested BelongsToMany with Api Resource

I need your help!
I'm having problems returning pivot table information when using ApiResources.
If I have a model like this:
Post.php
public function likes()
{
return $this->belongsToMany(Like::class)
->withPivot(['points']) // I want this in my PostResource::collection !
}
When defining its Resources:
LikeResource.php
public function toArray($request)
{
return [
'like_field' => $this->like_field
];
}
PostResource.php
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes'))
];
}
Then in PostController.php
return PostResource::collection(Post::with('likes')->get())
It will return something like this:
Controller Response
[
{
'title' => 'Post 1'
'likes' => [
{
'like_field' => 'Test'
},
{
'like_field' => 'Test 2'
}
]
},
{
'title' => 'Post 2',
...
}
]
The problem is, using that LikeResource::collection() it does not appends pivot information. How could I add 'points' of the pivot table when defining that PostResource??
Thats all,
Thx!
Solution
Well, simply reading a bit in Laravel Docs, to return pivot information you just has to use the method $this->whenPivotLoaded()
So, the PostResource becomes:
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes')),
'like_post' => $this->whenPivotLoaded('like_post', function() {
return $this->pivot->like_field;
})
];
}

Categories