Skip to content

Commit

Permalink
Merge pull request #6 from xi-project/2.1
Browse files Browse the repository at this point in the history
2.1 to master
  • Loading branch information
joonsp committed Sep 4, 2012
2 parents d05c573 + b95bbe0 commit 2ab0899
Show file tree
Hide file tree
Showing 15 changed files with 468 additions and 47 deletions.
15 changes: 8 additions & 7 deletions Controller/SearchController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

class SearchController extends Controller
{

public function searchAction()
{
{
$self = $this;
$service = $this->getSearchService();
$config = $this->container->getParameter('xi_search');
Expand All @@ -21,19 +21,20 @@ public function searchAction()
$limit = isset($config['default_limit']) ? $config['default_limit'] : null;

if($data->getSearchType() == 'search'){
$results = $service->search($data->getIndex(), $data->getTerm(), $limit);
$results = $service->searchPaginated($data->getIndex(), $data->getTerm(), $data->getPage(), $limit);
} elseif($data->getSearchType() == 'find') {
$results = $service->find($data->getIndex(), $data->getTerm(), $limit);

$results = $service->findPaginated($data->getIndex(), $data->getTerm(), $data->getPage(), $limit);
}

$resultHtml = $self->renderView('XiSearchBundle:Search:search.html.twig', array(
$resultHtml = $self->renderView('XiSearchBundle:Search:search_paginated.html.twig', array(
'results' => $results, 'index' => $data->getIndex(), 'options' => json_decode($data->getOptions())
));

return $self->createJsonSuccessWithContent($resultHtml, 'xiSearchResultCallback');
return $self->createJsonSuccessWithContent($resultHtml, 'xiSearchResultCallback');
});
}

/**
* @return SearchService
*/
Expand Down
36 changes: 36 additions & 0 deletions Event/Subscriber/ElasticaQuerySubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Xi\Bundle\SearchBundle\Event\Subscriber;

use Knp\Component\Pager\Event\ItemsEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Knp\Component\Pager\Event\Subscriber\Paginate\ElasticaQuerySubscriber as BaseSubscriber;

/**
* Elastica query pagination.
* Return the Elastica_ResultSet instead of it's results
*/
class ElasticaQuerySubscriber extends BaseSubscriber
{
/**
* @param ItemsEvent $event
*/
public function items(ItemsEvent $event)
{
if (is_array($event->target) && 2 === count($event->target) && isset($event->target[0], $event->target[1]) &&
$event->target[0] instanceof \Elastica_Searchable && $event->target[1] instanceof \Elastica_Query) {
list($searchable, $query) = $event->target;

$query->setFrom($event->getOffset());
$query->setLimit($event->getLimit());
$results = $searchable->search($query);

$event->count = $results->getTotalHits();
if ($results->hasFacets()) {
$event->setCustomPaginationParameter('facets', $results->getFacets());
}
$event->items = $results;
$event->stopPropagation();
}
}
}
14 changes: 11 additions & 3 deletions Form/ChoosableSearchType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,33 @@
namespace Xi\Bundle\SearchBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ChoosableSearchType extends SearchType
{

private $choices = array();

/**
* @param array $choices
*/
public function __construct($choices)
{
$this->choices = $choices;
}

public function buildForm(FormBuilder $builder, array $options)
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('options', 'hidden')
->add('options', 'hidden')
->add('index', 'choice', array('choices' => $this->choices, 'expanded' => true, 'label' => 'xi_search.choose-index'))
->add('searchType', 'hidden')
->add('page', 'hidden')
->add('term', 'text', array('label' => 'search.form.term.label'));
}

Expand Down
32 changes: 31 additions & 1 deletion Form/Model/SearchModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ class SearchModel
* @Assert\NotBlank(message="search.validation.term.notblank")
*/
protected $term;


/**
* @var int
*/
protected $page;

public function __construct()
{
$this->page = 1;
}

/**
* @param string $options
* @return \Xi\Bundle\SearchBundle\Form\Model\SearchModel
Expand Down Expand Up @@ -90,6 +100,7 @@ public function getSearchType()
public function setTerm($term)
{
$this->term = $term;

return $this;
}

Expand All @@ -100,4 +111,23 @@ public function getTerm()
{
return $this->term;
}

/**
* @param int $page
* @return \Xi\Bundle\SearchBundle\Form\Model\SearchModel
*/
public function setPage($page)
{
$this->page = $page;

return $this;
}

/**
* @return int
*/
public function getPage()
{
return $this->page;
}
}
30 changes: 22 additions & 8 deletions Form/SearchType.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,42 @@
namespace Xi\Bundle\SearchBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class SearchType extends AbstractType
{

public function buildForm(FormBuilder $builder, array $options)
{

/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('options', 'hidden')
->add('index', 'hidden')
->add('searchType', 'hidden')
->add('page', 'hidden')
->add('term', 'text', array('label' => 'search.form.term.label'));
}

/**
* @return string
*/
public function getName()
{
return 'xi_searchbundle_searchtype';
}

public function getDefaultOptions(array $options)

/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
return array('data_class' => 'Xi\Bundle\SearchBundle\Form\Model\SearchModel');
$resolver->setDefaults(array(
'data_class' => 'Xi\Bundle\SearchBundle\Form\Model\SearchModel',
));
}

}
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,28 @@ class App.AjaxForm.YourCustomClass extends App.AjaxForm.Default

Probably most easiest way to use this bundle is to use it with ElasticSearch because XiSearchBundle provides you
premade implementation for it. This however requires [FOQElasticaBundle](https://github.com/Exercise/FOQElasticaBundle) to work.

## Pagination
Pagination uses knp-pagination bundle, and it's on by default

Suppose the search is retrieved via ajax, there's a jquery plugin included that binds the received pagination's logic to the actual search form with javascript.

As the pagination generally uses the search forms default fields, only the indices need configuration. page, term and submit button values can also be overridden
``` coffee
$('#search-result-container').xiSearchPaginate
indices: ['#xi_searchbundle_searchtype_index_0', '#xi_searchbundle_searchtype_index_1', ...]
```

For these bindings to work, configure the knp pagination to use the proper pagination template
```yml
knp_paginator:
page_range: 9 # default page range used in pagination control
default_options:
page_name: page # page query parameter name
sort_field_name: sort # sort field query parameter name
sort_direction_name: direction # sort direction query parameter name
distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements
template:
pagination: XiSearchBundle:Pagination:sliding.html.twig # sliding pagination controls template
sortable: KnpPaginatorBundle:Pagination:sortable_link.html.twig # sort link template
```
28 changes: 28 additions & 0 deletions Resources/coffee/pagination.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
$ = jQuery
$.fn.xiSearchPaginate = (options) ->
defaultOptions =
page: '#xi_searchbundle_searchtype_page'
submit: '#xi_searchbundle_searchtype_submit'
term: '#xi_searchbundle_searchtype_term'
indices: []

options = $.extend true, {}, defaultOptions, options

# change page
@.on "click", ".pagination a", ->
pageValue = $(this).attr("data-page")
$(options.page).val pageValue
$(options.submit).find("button").trigger "click", silent: true

# reset page
$(options.term).change ->
$(options.page).val 1

if options.indices
for index in options.indices
$(index).change ->
$(options.page).val 1

$(options.submit).find("button").click (event, data) ->
unless data and data.silent
$(options.page).val 1
40 changes: 40 additions & 0 deletions Resources/views/Pagination/sliding.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{# default Sliding pagination control implementation #}

{% if pageCount > 1 %}
<div class="pages">
{% if first is defined and current != first %}
<span class="first">
<a href="#main-content" data-page="{{first}}">&lt;&lt;</a>
</span>
{% endif %}

{% if previous is defined %}
<span class="previous">
<a href="#main-content" data-page="{{previous}}">&lt;</a>
</span>
{% endif %}

{% for page in pagesInRange %}
{% if page != current %}
<span class="page">
<a href="#main-content" data-page="{{ page }}">{{ page }}</a>
</span>
{% else %}
<span class="current">{{ page }}</span>
{% endif %}

{% endfor %}

{% if next is defined %}
<span class="next">
<a href="#main-content" data-page="{{next}}">&gt;</a>
</span>
{% endif %}

{% if last is defined and current != last %}
<span class="last">
<a href="#main-content" data-page="{{last}}">&gt;&gt;</a>
</span>
{% endif %}
</div>
{% endif %}
12 changes: 12 additions & 0 deletions Resources/views/Search/search_paginated.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{# sorting of properties based on queried types..
<span>{{ pagination.sortable('Id', 'x.id')|raw }}</span>
#}

{% for result in results %}
{{ xi_search_result(result, options) }}
{% endfor %}
<div class="clear"></div>

<div class="pagination">
{{ results.render()|raw }}
</div>
2 changes: 1 addition & 1 deletion Resources/views/SearchForm/searchform.html.twig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<form action="{{ path('XiSearchBundle_search') }}" class="ajax-form article-form" method="post" {{ form_enctype(form) }}>
{{ form_widget(form.term, { 'attr': {'placeholder' : ('search.form.term.placeholder')|trans} }) }}
{{ form_rest(form) }}
<p>
<p id="xi_searchbundle_searchtype_submit">
<button type="submit">{{'search.form.submit_button'|trans}}</button>
</p>
</form>
Loading

0 comments on commit 2ab0899

Please sign in to comment.