User search refactored, autocomplete added. bootstrap3-typeahead jQuery plugin added.
This commit is contained in:
parent
d71ea8a116
commit
d0c103eae0
|
@ -35,6 +35,9 @@ sensio_framework_extra:
|
|||
|
||||
# Twig Configuration
|
||||
twig:
|
||||
form:
|
||||
resources:
|
||||
- bootstrap_3_layout.html.twig
|
||||
debug: "%kernel.debug%"
|
||||
strict_variables: "%kernel.debug%"
|
||||
|
||||
|
|
|
@ -3,17 +3,42 @@
|
|||
namespace Skobkin\Bundle\PointToolsBundle\Controller;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Skobkin\Bundle\PointToolsBundle\Form\UserSearchType;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class MainController extends Controller
|
||||
{
|
||||
public function indexAction()
|
||||
public function indexAction(Request $request)
|
||||
{
|
||||
/** @var EntityManager $em */
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$form = $this->createForm(
|
||||
new UserSearchType(),
|
||||
null,
|
||||
[
|
||||
'action' => $this->generateUrl('index'),
|
||||
'method' => 'POST',
|
||||
]
|
||||
);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$login = $form->get('login')->getData();
|
||||
|
||||
if (null !== $user = $em->getRepository('SkobkinPointToolsBundle:User')->findOneBy(['login' => $login])) {
|
||||
return $this->redirectToRoute('user_show', ['login' => $login]);
|
||||
}
|
||||
|
||||
$form->get('login')->addError(new FormError('Login not found'));
|
||||
}
|
||||
|
||||
return $this->render('SkobkinPointToolsBundle:Main:index.html.twig', [
|
||||
'form' => $form->createView(),
|
||||
'users_count' => $em->getRepository('SkobkinPointToolsBundle:User')->getUsersCount(),
|
||||
'subscribers_count' => $em->getRepository('SkobkinPointToolsBundle:Subscription')->getUserSubscribersCountById($this->container->getParameter('point_id')),
|
||||
'events_count' => $em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->getLastDayEventsCount(),
|
||||
|
@ -21,4 +46,20 @@ class MainController extends Controller
|
|||
'last_events' => $em->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->getLastSubscriptionEvents(10),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchUserAjaxAction($login)
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($em->getRepository('SkobkinPointToolsBundle:User')->findUsersLikeLogin($login) as $user) {
|
||||
$result[] = [
|
||||
'login' => $user->getLogin(),
|
||||
'name' => $user->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
return new JsonResponse($result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,19 +50,6 @@ class UserController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
public function searchUserAction(Request $request)
|
||||
{
|
||||
$login = $request->request->get('login');
|
||||
|
||||
if (!$login) {
|
||||
return $this->redirectToRoute('index');
|
||||
}
|
||||
return $this->redirectToRoute('user_show', ['login' => $login]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TopUserDTO[] $topUsers
|
||||
* @return Highchart
|
||||
|
|
39
src/Skobkin/Bundle/PointToolsBundle/Form/UserSearchType.php
Normal file
39
src/Skobkin/Bundle/PointToolsBundle/Form/UserSearchType.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Skobkin\Bundle\PointToolsBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class UserSearchType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* @param FormBuilderInterface $builder
|
||||
* @param array $options
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('login')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => 'Skobkin\Bundle\PointToolsBundle\Entity\User',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'skobkin_bundle_pointtoolsbundle_user_search';
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ class UserRepository extends EntityRepository
|
|||
* Case-insensitive user search
|
||||
*
|
||||
* @param string $login
|
||||
* @return User[]
|
||||
* @return User|null
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
*/
|
||||
public function findUserByLogin($login)
|
||||
|
@ -28,6 +28,31 @@ class UserRepository extends EntityRepository
|
|||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Case insensitive user LIKE %login% search
|
||||
*
|
||||
* @param string $login
|
||||
*
|
||||
* @return User[]
|
||||
*/
|
||||
public function findUsersLikeLogin($login)
|
||||
{
|
||||
if (empty($login)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$qb = $this->createQueryBuilder('u');
|
||||
|
||||
return $qb
|
||||
->where('u.login LIKE :login')
|
||||
->orderBy('u.login', 'ASC')
|
||||
->setMaxResults(10)
|
||||
->setParameter('login', '%'.strtolower($login).'%')
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
|
|
|
@ -2,10 +2,12 @@ index:
|
|||
path: /
|
||||
defaults: { _controller: SkobkinPointToolsBundle:Main:index }
|
||||
|
||||
user_search:
|
||||
path: /user/search
|
||||
defaults: { _controller: SkobkinPointToolsBundle:User:searchUser }
|
||||
methods: [POST]
|
||||
user_search_ajax:
|
||||
path: /ajax/users/search/{login}
|
||||
defaults: { _controller: SkobkinPointToolsBundle:Main:searchUserAjax, _format: json }
|
||||
requirements:
|
||||
login: "[\w-]*"
|
||||
_format: json
|
||||
|
||||
user_show:
|
||||
path: /user/{login}
|
||||
|
|
|
@ -1,18 +1,52 @@
|
|||
{% extends "::base.html.twig" %}
|
||||
|
||||
{% block head_js %}
|
||||
{{ parent() }}
|
||||
<script src="{{ asset('js/bootstrap3-typeahead.min.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="well well-lg">
|
||||
{# @todo rewrite to Symfony forms #}
|
||||
<form class="form-inline" method="post" action="{{ path('user_search') }}">
|
||||
{{ form_start(form, {'attr': {'class': 'form-inline'} }) }}
|
||||
<div class="form-group">
|
||||
<label class="sr-only" for="index-input-username">{{ 'Username'|trans }}</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">@</div>
|
||||
<input name="login" type="text" class="form-control" id="index-input-username" placeholder="username">
|
||||
{{ form_errors(form.login) }}
|
||||
{{ form_widget(form.login, {'attr': {'autocomplete': 'off'}}) }}
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$field = $('#{{ form.login.vars.id }}');
|
||||
|
||||
$field.typeahead({
|
||||
minLength: 2,
|
||||
delay: 500,
|
||||
autoSelect: true,
|
||||
source: function (query, processCallback) {
|
||||
$.get('{{ path('user_search_ajax', {'login': ''}) }}' + query, function (data) {
|
||||
processCallback(data);
|
||||
});
|
||||
},
|
||||
afterSelect: function () {
|
||||
$field.parents('form').first().submit();
|
||||
},
|
||||
displayText: function (item) {
|
||||
// Crutches to place only login into the field after selecting the item
|
||||
if (typeof item === 'object') {
|
||||
return item.login+(item.name ? ' ('+item.name+')' : '');
|
||||
} else if (typeof item === 'string') {
|
||||
return item;
|
||||
}
|
||||
},
|
||||
updater: function (item) {
|
||||
// Crutches to place only login into the field after selecting the item
|
||||
return item.login;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<input type="submit" value="{{ 'Search'|trans }}" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">{{ 'Search'|trans }}</button>
|
||||
</form>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
|
||||
<div class="container service-stats">
|
||||
|
|
1
web/js/bootstrap3-typeahead.min.js
vendored
Normal file
1
web/js/bootstrap3-typeahead.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue