Provides a way to make entities searchable.
Searches will be sorted by relevance which is calculated using the weight you can configure to the fields you index.
Require the bundle using composer:
composer require demontpx/rigid-search-bundle
Lets say we want to index a NewsItem
entity:
class NewsItem {
public function getId() { return $this->id; }
public function getTitle() { return $this->title; }
// ...
}
The first step is to create a new class which implements the SearchDocumentExtractorInterface
. In here you define in which fields there needs to be searched and how important they are in relation to each other.
class NewsItemDocumentExtractor implements SearchDocumentExtractorInterface {
public function extractDocument($item): Document {
// $item should be of the type NewsItem
// The title, description and URL you put in here are only used for display and link to the item
// They are not searchable unless you add them as fields as well (see below!)
$document = new Document(
$item->getTitle(),
$item->getDescription(),
$item->getPublishDate(),
$this->generateUrl($item)
);
// These are the fields on which items can be found
// The last argument are the weight values, which can be any relative number
$document->addField(new Field('title', $item->getTitle(), 1.0);
$document->addField(new Field('text', $item->getText(), 0.8);
$document->addField(new Field('category', $item->getCategoryName(), 0.2);
$document->addField(new Field('tags', implode(' ', $item->getTagList()->toArray()), 0.25);
return $document;
}
public function extractId($item): int {
return $item->getId();
}
}
Step two is to create another new class which implements the ItemSearchManagerInterface
:
class NewsItemSearchManager implements ItemSearchManagerInterface {
public function getClass(): string {
// Classname of the entity
return NewsItem::class;
}
public function getType(): string {
// Short arbitrary unique name to describe the entity
return 'news';
}
public function getDocumentExtractor(): SearchDocumentExtractorInterface {
// Return the class created earlier
// You could, of course, also inject the extractor into this class using the service container and pass it here
return new NewsItemDocumentExtractor();
}
public function fetchAll(): array {
// This method should return all searchable items of this type (ie: only published news items)
// This is used when reindexing all items of this type
// You should figure out for yourself where these entities should come from
// For example: get these from an EntityRepository
return $this->repository->fetchAllPublished();
}
}
Register this class as a service in the container:
MyBundle\NewsItemSearchManager:
tags: [demontpx_rigid_search.item_search_manager]
If everything is configured correctly, you should be able to index all news
items using this command:
bin/console demontpx:search:reindex:type news
The next step is to trigger the index and remove manually when a news item is created, updated or removed. This could be achieved using events, or you could manually index and remove items from your search index in the controller:
class NewsItemController extends Controller {
public function newAction() {
$item = new NewsItem();
// ... Do your persist logic here
$searchManager = $this->get('demontpx_rigid_search.search_manager');
$searchManager->index($item);
}
public function editAction(NewsItem $item) {
// ... Do your persist logic here
$searchManager = $this->get('demontpx_rigid_search.search_manager');
$searchManager->index($item);
}
public function removeAction(NewsItem $item) {
$oldId = $item->getId();
// ... Do your remove logic here
$searchManager = $this->get('demontpx_rigid_search.search_manager');
$searchManager->remove($item);
// Doctrine ORM resets the item id to null after a delete, so you might want to use this:
$searchManager->removeByClassAndId(get_class($item), $oldId);
}
}
The first step is to add this to your routing.yaml
:
demontpx_rigid_search:
resource: "@DemontpxRigidSearchBundle/Resources/config/routing.yml"
prefix: /search
After that you could add this to any of your twig templates:
{{ render(controller('Demontpx\\RigidSearchBundle\\Controller\\SearchController::searchForm', {}, { query: app.request.query.get('query', '') })) }}
Which will add the search input field. When submitted, this will show the search result.
The search result page will extend the ::base.html.twig
template by default. Override the whole template by creating app/Resources/DemontpxRigidSearchBundle/views/Search/searchResult.html.twig
.