PHP code example of tobento / app-search

1. Go to this page and download the library: Download tobento/app-search library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

tobento / app-search example snippets


use Tobento\App\AppFactory;
use Tobento\App\Search\InputInterface;
use Tobento\App\Search\SearchInterface;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\Search\Boot\Search::class);
$app->booting();

// Implemented interfaces:
$search = $app->get(SearchInterface::class);
$input = $app->get(InputInterface::class);

// Run the app
$app->run();

use Tobento\App\Search\Filters;
use Tobento\App\Search\FiltersInterface;
use Tobento\App\Search\Input;
use Tobento\App\Search\InputInterface;
use Tobento\App\Search\Search;
use Tobento\App\Search\Searchables;
use Tobento\App\Search\SearchablesInterface;
use Tobento\App\Search\SearchInterface;
use Tobento\App\Search\SearchResultsInterface;

$search = new Search(
    filters: new Filters(), // FiltersInterface
    searchables: new Searchables(), // SearchablesInterface
);

var_dump($search instanceof SearchInterface);
// bool(true)

// Searching:
$searchResults = $search->search(
    input: new Input(['search' => ['term' => 'foo']]), // InputInterface
);

var_dump($searchResults instanceof SearchResultsInterface);
// bool(true)

// You may get the filters:
var_dump($search->filters() instanceof FiltersInterface);
// bool(true)

// You may get the searchables:
var_dump($search->searchables() instanceof SearchablesInterface);
// bool(true)

'features' => [
    new Feature\Search(
        // The default views to render:
        view: 'search/index',
        viewSearchbar: 'search/searchbar',
        viewSearchbarResults: 'search/searchbar-results',
        
        // You may customize the searchbar input placeholder:
        searchbarInputPlaceholder: 'Search...',
        
        // If true, routes are being localized.
        localizeRoute: false,
    ),
],

<header><?= $view->render('search.bar') 

use Psr\Container\ContainerInterface;
use Tobento\App\Search\Search;
use Tobento\App\Search\Searchable;
use Tobento\App\Search\Searchables;
use Tobento\App\Search\SearchInterface;
use Tobento\App\Search\Filter;
use Tobento\App\Search\Filters;

'interfaces' => [
    SearchInterface::class => static function(ContainerInterface $container): SearchInterface {
        return new Search(
            filters: new Filters(
                new Filter\SearchTerm(name: 'search.term'),
            ),
            searchables: new Searchables(
                new Searchable\Menus($container->get(\Tobento\Service\Menu\MenusInterface::class)->menu('main')),
            ),
        );
    },
],

use Tobento\App\Search\Searchable;
use Tobento\App\Search\SearchablesInterface;
use Tobento\App\Search\SearchInterface;

$app->on(
    SearchInterface::class,
    static function(SearchInterface $search) use ($app): void {
        // Get the searchables:
        $searchables = $search->searchables();
        // SearchablesInterface
        
        // Adding a searchable:
        $menu = $app->get(\Tobento\Service\Menu\MenusInterface::class)->menu('main');
        $searchables->add(searchable: new Searchable\Menus(menu: $menu));
    }
);

use Tobento\App\Search\Filter;
use Tobento\App\Search\FilterInterface;
use Tobento\App\Search\FiltersInterface;
use Tobento\App\Search\SearchableInterface;
use Tobento\App\Search\SearchResult;
use Tobento\App\Search\SearchResultInterface;
use Tobento\Service\Pagination\Pagination;
use Tobento\Service\Pagination\PaginationInterface;
use Tobento\Service\Pagination\UrlGenerator;
use Tobento\Service\View\ViewInterface;

class ProductsSearchable implements SearchableInterface
{
    protected null|PaginationInterface $pagination = null;
    
    public function __construct(
        protected ProductRepository $repository,
        protected ViewInterface $view,
        protected int $priority = 0,
    ) {}
    
    public function name(): string
    {
        return 'products';
    }
    
    public function title(): string
    {
        return 'Products';
    }
    
    public function priority(): int
    {
        return $this->priority;
    }
    
    /**
     * Returns the filters.
     *
     * @return array<array-key, FilterInterface>
     */
    public function filters(): array
    {
        // Configure specific products filters defining the searchable attribute on each filter:
        return [
            new Filter\Select(
                name: 'search.product-color',
                label: 'Colors',
                searchable: $this->name(),
                options: ['red' => 'Red', 'blue' => 'Blue'],
            ),
            new Filter\Pagination(
                name: 'search.product-page',
                searchable: $this->name(),
                pagination: $this->pagination(),
            ),
        ];
    }
    
    /**
     * Returns the search results found.
     *
     * @param FiltersInterface $filters
     * @return array<array-key, SearchResultInterface>
     */
    public function search(FiltersInterface $filters): array
    {
        $where = [];
        $orderBy = [];
        $limit = [];
        
        // Use the filters you wish to apply to your query:
        foreach($filters as $filter) {
            switch ($filter::class) {
                case Filter\Select::class:
                    if ($filter->name() === 'search.product-color') {
                        // apply filter to query:
                    }
                    break;
                case Filter\SearchTerm::class:
                    // apply filter to query:
                    break;
                case Filter\Pagination::class:
                    if ($filter->name() === 'search.product-page') {
                        $this->pagination = $filter->pagination();
                        $limit = [$this->pagination->getItemsPerPage(), $this->pagination->getItemsOffset()];
                    }
                    break;
            }
        }
        
        if ($filters->has('search.product-page')) {
            $paginationFilter = $filters->get('search.product-page');
            $paginationFilter->updatePaginationTotalItems($this->repository->count(where: $where));
            $this->pagination = $paginationFilter->pagination();
            $limit = [$this->pagination->getItemsPerPage(), $this->pagination->getItemsOffset()];
        }
        
        // Do the query and create the search results:
        $results = [];
        
        foreach($this->repository->findAll(where: $where, orderBy: $orderBy, limit: $limit) as $item) {
            $results = new SearchResult(
                searchable: $this->name(),
                type: $this->title(),
                title: $item->get('title'),
                url: $item->get('url'),
                image: $item->get('image'),
                
                // you may add html for custom search result:
                html: $this->view->render(
                    view: 'product/search-result',
                    data: $item,
                ),
            );
        }
        
        return $results;
    }

    public function totalItems(): int
    {
        return $this->pagination()->getTotalItems();
    }
    
    public function pagination(): PaginationInterface
    {
        if ($this->pagination) {
            return $this->pagination;
        }
        
        return $this->pagination = new Pagination(
            totalItems: $this->repository->count(),
            currentPage: 1,
            itemsPerPage: 25,
            maxPagesToShow: 6,
            maxItemsPerPage: 100,
            urlGenerator: (new UrlGenerator())->addPageUrl('?search[product-page]={num}'),
        );
    }
}

use Psr\Container\ContainerInterface;
use Tobento\App\Search\Search;
use Tobento\App\Search\Searchable;
use Tobento\App\Search\Searchables;
use Tobento\App\Search\SearchInterface;
use Tobento\App\Search\Filter;
use Tobento\App\Search\Filters;

'interfaces' => [
    SearchInterface::class => static function(ContainerInterface $container): SearchInterface {
        return new Search(
            filters: new Filters(
                new Filter\SearchTerm(name: 'search.term'),
            ),
            searchables: new Searchables(
                new Searchable\Menus($container->get(\Tobento\Service\Menu\MenusInterface::class)->menu('main')),
            ),
        );
    },
],

use Tobento\App\Search\Filter;
use Tobento\App\Search\FiltersInterface;
use Tobento\App\Search\SearchInterface;

$app->on(
    SearchInterface::class,
    static function(SearchInterface $search) use ($app): void {
        // Get the filters:
        $filters = $search->filters();
        // FiltersInterface
        
        // Adding a filter:
        $filters->add(filter: new Filter\SearchTerm(name: 'search.term'));
    }
);

use Tobento\App\Search\Searchable;
use Tobento\Service\Menu\MenuInterface;

$searchable = new Searchable\Menu(
    menu: $menu, // MenuInterface
    
    // Set a unique name:
    name: 'menu',
    
    // You may set a custom title:
    title: 'Menu Items',
    
    // You may set a priority:
    priority: 100,
);

use Tobento\App\Search\Searchable;
use Tobento\App\Search\SearchResult;
use Tobento\App\Search\SearchResultInterface;
use Tobento\Service\Repository\RepositoryInterface;

$searchable = new Searchable\Repository(
    repository: $repository, // RepositoryInterface
    
    // Set a unique name:
    name: 'products',
    
    // Set a title:
    title: 'Products',
    
    // Define the search attributes:
    searchAttributes: ['title', 'description'],
    
    // Map the repository items to the search results:
    toSearchResult: function(object $item, Searchable\Repository $searchable): SearchResultInterface {
        return new SearchResult(
            searchable: $searchable->name(),
            type: $searchable->title(),
            title: $item->get('title'),
            description: $item->get('description'),
            url: $item->get('url'),
            image: $item->get('image'),
        );
    },
    
    // You may set a priority:
    priority: 100,
);

use Tobento\App\Search\Filter;

$filter = new Filter\Clear(
    // Set a unique name:
    name: 'search.clear',
    
    // You may set a custom label:
    label: 'Clear all',
    
    // You may set attributes for the button element:
    attributes: ['data-foo' => 'value'],
);

use Tobento\App\Search\Filter;

$filter = new Filter\Input(
    // Set a unique name:
    name: 'search.price.from',
    
    // You may set a label:
    label: 'Price From',
    
    // You may set a description:
    description: 'Searches prices from.',
    
    // You may set a searchable the filter belongs to:
    searchable: 'products', // or null
    
    // You may change the default input type (text):
    inputType: 'range',
    
    // You may set attributes for the input element:
    inputAttributes: ['min' => '5'],
    
    // You may set a default input value:
    inputValue: '10', // or null
    
    // You may set a custom view to render:
    view: 'search/filter',
);

use Tobento\App\Search\Filter;

$filter = new Filter\Searchables(
    // Set a unique name:
    name: 'search.searchables',
    
    // You may set a custom label:
    label: 'Content',
    
    // You may set a description:
    description: 'Choose the contents you wish to search.',
    
    // You may set a custom view to render:
    view: 'search/filter',
);

use Tobento\App\Search\Filter;

$filter = new Filter\SearchTerm(
    // Set a unique name:
    name: 'search.term',
    
    // You may set a label:
    label: 'Search',
    
    // You may set a description:
    description: 'Search for ...',
    
    // You may set a custom placeholder text:
    placeholder: 'Search ...',
    
    // You may set a custom view to render:
    view: 'search/filter',
);

use Tobento\App\Search\Filter;

$filter = new Filter\Select(
    // Set a unique name:
    name: 'search.colors',
    
    // You may set a label:
    label: 'Colors',
    
    // You may set a description:
    description: 'Choose any colors you wish to search for.',
    
    // You may set a searchable the filter belongs to:
    searchable: 'products', // or null
    
    // Set the options to choose from:
    options: ['blue' => 'Blue', 'red' => 'Red'],
    // with optgroup options:
    // options: ['Primary' => ['blue' => 'Blue']],
    
    // You may set a default value:
    selected: ['blue'],
    
    // You may set attributes for the select element:
    selectAttributes: ['multiple'],
    
    // You may set attributes for the option elements:
    optionAttributes: ['*' => ['data-foo' => 'val']],
    
    // You may set attributes for the optgroup elements:
    optgroupAttributes: ['data-foo' => 'value'],
    
    // You may set a custom view to render:
    view: 'search/filter',
);
app/config/search.php