knplabs/knp-components
Knp Components is a PHP component library from KnpLabs. It currently includes the Pager component for building flexible, “fancy” pagination and paging adapters. PHPUnit 10/11 supported; install with Composer and run the test suite via composer test.
## Getting Started
### **First Steps**
1. **Installation**
```bash
composer require knplabs/knp-components:^5.2.0
Register the service provider in config/app.php under providers:
KnpLabs\KnpComponents\ComponentProvider::class,
Basic Usage The package provides a component-based architecture for reusable UI elements (e.g., paginators, modals, alerts). Start by exploring the built-in components:
First Use Case: Paginator
use KnpLabs\KnpComponents\Component\Paginator\PaginatorComponent;
// In a controller or service
$paginator = new PaginatorComponent(
$items, // Your collection/array
$currentPage,
$perPage,
$totalItems
);
// Pass to Blade
return view('your.view', ['paginator' => $paginator]);
In Blade:
{!! $paginator->render() !!}
Note: v5.2.0 removes the ORDER BY clause from item count queries (PR #348), improving performance for large datasets.
Reusable Components: Extend or override built-in components (e.g., PaginatorComponent) to fit your design system.
class CustomPaginator extends PaginatorComponent
{
public function render(): string
{
// Customize rendering logic
return '<div class="custom-paginator">' . parent::render() . '</div>';
}
}
Dependency Injection: Components accept dependencies (e.g., ViewRenderer, UrlGenerator) via constructor. Use Laravel’s DI container for flexibility.
New: The knp_pager.items event now passes an ArgumentAccess object (PR #343), enabling granular access to paginator arguments for event listeners.
Dynamic Rendering: Components can be rendered conditionally:
@if($hasItems)
{!! $paginator->render() !!}
@endif
Slot-Based Layouts: Use Blade slots for customizable sections (e.g., modal headers/footers):
{!! $modal->render([
'header' => '<h3>Custom Header</h3>',
'footer' => '<button>Close</button>',
]) !!}
Server-Side Pagination: Fetch paginated data via API (e.g., Laravel’s paginate()) and pass it to the component:
$items = YourModel::paginate(10);
$paginator = new PaginatorComponent($items->items(), $items->currentPage(), $items->perPage(), $items->total());
Optimization: v5.2.0 ensures accurate item counts without unnecessary ORDER BY clauses (PR #348).
AJAX Updates: Use JavaScript to update paginators dynamically (e.g., infinite scroll):
document.querySelector('.paginator-next').addEventListener('click', (e) => {
fetch(`/api/items?page=${nextPage}`)
.then(response => response.json())
.then(data => {
// Update DOM with new paginator component
});
});
Listen to Paginator Events: Leverage the knp_pager.items event with the new ArgumentAccess object:
use KnpLabs\KnpComponents\Component\Paginator\Event\PaginatorItemsEvent;
use Symfony\Component\OptionsResolver\ArgumentAccess;
Event::listen(PaginatorItemsEvent::class, function (PaginatorItemsEvent $event) {
$access = $event->getArgumentAccess();
$currentPage = $access->get('currentPage');
// Custom logic based on paginator arguments
});
Testing Components: Mock dependencies (e.g., ViewRenderer) to test component logic:
$viewRenderer = Mockery::mock(ViewRenderer::class);
$paginator = new PaginatorComponent([], 1, 10, 100, $viewRenderer);
$this->assertStringContainsString('page 1', $paginator->render());
Blade vs. Plain PHP Rendering
renderAsString() or renderToResponse():
$html = $paginator->renderAsString();
URL Generation in Components
UrlGenerator. If URLs are incorrect, verify:
APP_URL in .env.UrlGenerator is bound correctly in the DI container.Component State Management
// In a controller
session(['modal_open' => true]);
@if(session('modal_open'))
{!! $modal->render() !!}
@endif
Item Count Accuracy (v5.2.0)
ORDER BY clauses from item count queries, preventing performance issues with large datasets. Ensure your queries return correct totals without implicit ordering.Inspect Rendered HTML
Use dd($paginator->render()) to debug output before passing to Blade.
Override Default Templates
Components use Blade templates under resources/views/vendor/knp-components/. Override them by copying to your project:
cp vendor/knplabs/knp-components/resources/views/vendor/knp-components/* resources/views/vendor/knp-components/
Custom CSS/JS Components include minimal styling. Extend with your own assets:
<link rel="stylesheet" href="{{ asset('css/paginator.css') }}">
{!! $paginator->render() !!}
Event Debugging
ArgumentAccess in event listeners to inspect paginator arguments:
$event->getArgumentAccess()->get('totalItems');
Create Custom Components
Extend AbstractComponent to build domain-specific components:
class UserCardComponent extends AbstractComponent
{
public function __construct(private User $user) {}
public function render(): string
{
return view('components.user-card', ['user' => $this->user])->render();
}
}
Hook into Component Events
Use events (e.g., PaginatorComponent::PAGE_CHANGED) or the new knp_pager.items with ArgumentAccess for analytics or logging:
event(new PaginatorPageChanged($currentPage, $totalPages));
Localization
Components support localization via Laravel’s translation system. Override default strings in lang/en/knp-components.php:
return [
'paginator' => [
'previous' => '« Previous',
'next' => 'Next »',
],
];
Performance Optimization (v5.2.0)
total() method does not include ORDER BY clauses to avoid performance degradation:
// Example: Avoid this in your total() query
YourModel::orderBy('id')->count();
// Instead, rely on the component's optimized count logic
NO_UPDATE_NEEDED would not apply here due to the meaningful changes in v5.2.0.
How can I help you explore Laravel packages today?