X

en une seule collection avec pagination


Dans ce didacticiel, nous allons créer une recherche simple à partir de trois modèles et utiliser les collections Laravel pour les combiner en une seule collection afin d’afficher les résultats dans le front-end.

De plus, nous ferons en sorte que la couleur d’arrière-plan de la ligne du tableau soit basée sur le modèle. Et enfin, nous ajouterons la pagination à la Collection pour afficher les résultats avec les liens de pagination.

Au final, nous aurons un résultat similaire à celui-ci :


La structure de la base de données ici est très simple. Nous avons trois modèles Post, Videoet Courseet chacun a un title colonne. Les données prédéfinies ressembleraient à ceci :

Maintenant, pour le contrôleur où la recherche se produit. Dans le formulaire de recherche, l’entrée porte le nom de query et parce que le formulaire utilise le OBTENIR méthode, après avoir soumis le formulaire, nous obtenons une URL similaire à /search?query=. Dans le contrôleur, nous pouvons obtenir le query paramètre à l’aide de Request. En utilisant tout cela, nous pouvons rechercher ceci :

use Illuminate\Http\Request;

 

class SearchController extends Controller

{

public function __invoke(Request $request)

{

$posts = Post::where('title', 'like', '%' . $request->input('query') . '%')->get();

$courses = Course::where('title', 'like', '%' . $request->input('query') . '%')->get();

$videos = Video::where('title', 'like', '%' . $request->input('query') . '%')->get();

}

}

Maintenant que nous avons tous les résultats, nous pouvons les ajouter à une collection. Pour ce faire, nous devons d’abord créer une nouvelle collection et utiliser le push() méthode pour ajouter des éléments à la fin de la collection.

class SearchController extends Controller

{

public function __invoke(Request $request)

{

$posts = Post::where('title', 'like', '%' . $request->input('query') . '%')->get();

$courses = Course::where('title', 'like', '%' . $request->input('query') . '%')->get();

$videos = Video::where('title', 'like', '%' . $request->input('query') . '%')->get();

 

$results = collect();

 

$results->push($posts, $courses, $videos);

}

}

Après ça, $results donnera un résultat similaire à ceci:

Illuminate\Support\Collection {#302 ▼ // app/Http/Controllers/SearchController.php:21

#items: array:3 [▼

0 => Illuminate\Database\Eloquent\Collection {#1043 ▼

#items: array:2 [▼

0 => App\Models\Post {#1255 ▶}

1 => App\Models\Post {#1256 ▶}

]

#escapeWhenCastingToString: false

}

1 => Illuminate\Database\Eloquent\Collection {#1257 ▼

#items: array:3 [▼

0 => App\Models\Course {#1260 ▶}

1 => App\Models\Course {#1261 ▶}

2 => App\Models\Course {#1262 ▶}

]

#escapeWhenCastingToString: false

}

2 => Illuminate\Database\Eloquent\Collection {#1109 ▼

#items: array:3 [▼

0 => App\Models\Video {#1265 ▶}

1 => App\Models\Video {#1266 ▶}

2 => App\Models\Video {#1267 ▶}

]

#escapeWhenCastingToString: false

}

]

#escapeWhenCastingToString: false

}

Mais dans cette structure, nous ne pouvons pas parcourir facilement toutes les données. Maintenant, nous devons transformer cette collection multidimensionnelle en une seule dimension. Pour cela, il suffit d’utiliser le flatten() méthode et renvoie le résultat à la vue.

class SearchController extends Controller

{

public function __invoke(Request $request)

{

$posts = Post::where('title', 'like', '%' . $request->input('query') . '%')->get();

$courses = Course::where('title', 'like', '%' . $request->input('query') . '%')->get();

$videos = Video::where('title', 'like', '%' . $request->input('query') . '%')->get();

 

$results = collect();

 

$results->push($posts, $courses, $videos);

 

return view('search', ['results' => $results->flatten()]);

}

}

Maintenant, nous avons une collection dans une belle structure facilement itérable.

Illuminate\Support\Collection {#308 ▼ // app/Http/Controllers/SearchController.php:21

#items: array:8 [▼

0 => App\Models\Post {#1255 ▶}

1 => App\Models\Post {#1256 ▶}

2 => App\Models\Course {#1260 ▶}

3 => App\Models\Course {#1261 ▶}

4 => App\Models\Course {#1262 ▶}

5 => App\Models\Video {#1265 ▶}

6 => App\Models\Video {#1266 ▶}

7 => App\Models\Video {#1267 ▶}

]

#escapeWhenCastingToString: false

}

Il ne reste plus qu’à afficher les résultats. Nous pouvons simplement utiliser @forelse passer en revue tous les résultats, et @empty écrire si aucun résultat n’a été trouvé. Et en utilisant instanceof nous pouvons modifier l’arrière-plan de la ligne du tableau pour un résultat spécifique.

<tbody class="bg-white divide-y divide-gray-200 divide-solid">

@forelse($results as $result)

<tr @class([

'bg-green-50' => $result instanceof App\Models\Post,

'bg-indigo-50' => $result instanceof App\Models\Video,

'bg-amber-50' => $result instanceof App\Models\Course,

])>

<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">

{{ $result->title }}

</td>

<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">

{{ $result->created_at }}

</td>

</tr>

@empty

No results found.

@endforelse

</tbody>


Bien sûr, vous pourriez avoir de nombreux résultats, et pour cela, vous voudriez paginer les résultats. Mais les collections n’ont pas de méthode prête à l’emploi pour paginer. Pour ce faire, nous avons deux façons. L’une consiste à utiliser le package spatie/laravel-collection-macros et l’autre à créer vous-même une macro. Le code dans les deux sens sera le même. Pour ajouter des macros, vous devez généralement les ajouter dans le boot() d’un prestataire de services.

use Illuminate\Support\Collection;

use Illuminate\Support\ServiceProvider;

use Illuminate\Pagination\LengthAwarePaginator;

 

class AppServiceProvider extends ServiceProvider

{

//

public function boot(): void

{

Collection::macro('paginate', function ($perPage = 15, $total = null, $page = null, $pageName = 'page') {

$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);

 

return new LengthAwarePaginator(

$this->forPage($page, $perPage),

$total ?: $this->count(),

$perPage,

$page,

[

'path' => LengthAwarePaginator::resolveCurrentPath(),

'pageName' => $pageName,

]

);

});

}

}

Maintenant, vous pouvez ajouter le paginate() méthode à la $results.

class SearchController extends Controller

{

public function __invoke(Request $request)

{

$posts = Post::where('title', 'like', '%' . $request->input('query') . '%')->get();

$courses = Course::where('title', 'like', '%' . $request->input('query') . '%')->get();

$videos = Video::where('title', 'like', '%' . $request->input('query') . '%')->get();

 

$results = collect();

 

$results->push($posts, $courses, $videos);

 

return view('search', ['results' => $results->flatten()]);

return view('search', ['results' => $results->flatten()->paginate()]);

}

}

N’oubliez pas, lors de l’ajout links() afficher la pagination, ajouter withQueryString() de sorte que lorsque vous parcourez des pages $query paramètre serait ajouté.

{{ $results->withQueryString()->links() }}


C’est tout pour ce tutoriel. Si vous voulez en savoir plus sur les Collections et surtout comment les utiliser dans des chaînes avec des exemples concrets, vous pouvez regarder le cours vidéo Laravel Collections Chains : 15 Real Examples ou lire le tutoriel Premium Laravel Collections : 15 Open-Source Exemples de méthodes “chaînées”.