Top users page. SQL queries optimization.

This commit is contained in:
Alexey Skobkin 2015-05-31 09:16:10 +03:00
parent f19efe8ca1
commit ce0b6e856f
5 changed files with 80 additions and 7 deletions

View file

@ -25,7 +25,7 @@
{% block header_navbar_menus %} {% block header_navbar_menus %}
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="{{ path('index') }}"><span class="glyphicon glyphicon-home"></span> {{ 'Main'|trans }}</a></li> <li><a href="{{ path('index') }}"><span class="glyphicon glyphicon-home"></span> {{ 'Main'|trans }}</a></li>
<li><a href="{{ path('users_top') }}"><span class="glyphicon glyphicon-stats"></span> TOP</a></li> <li><a href="{{ path('users_top') }}"><span class="glyphicon glyphicon-stats"></span> {{ 'Top'|trans }}</a></li>
</ul> </ul>
{% endblock %} {% endblock %}
</div> </div>

View file

@ -2,9 +2,10 @@
namespace Skobkin\Bundle\PointToolsBundle\Controller; namespace Skobkin\Bundle\PointToolsBundle\Controller;
use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Skobkin\Bundle\PointToolsBundle\Entity\TopUserDTO;
use Skobkin\Bundle\PointToolsBundle\Entity\User; use Skobkin\Bundle\PointToolsBundle\Entity\User;
use Skobkin\Bundle\PointToolsBundle\Service\UserApi; use Skobkin\Bundle\PointToolsBundle\Service\UserApi;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller;
@ -12,7 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class UserController extends Controller class UserController extends Controller
{ {
/** /**
* @param * @param User $user
* @ParamConverter("user", class="SkobkinPointToolsBundle:User", options={"login" = "login"}) * @ParamConverter("user", class="SkobkinPointToolsBundle:User", options={"login" = "login"})
*/ */
public function showAction(User $user) public function showAction(User $user)
@ -20,19 +21,30 @@ class UserController extends Controller
$userApi = $this->container->get('skobkin_point_tools.api_user'); $userApi = $this->container->get('skobkin_point_tools.api_user');
/** @var QueryBuilder $qb */ /** @var QueryBuilder $qb */
$qb = $this->getDoctrine()->getManager()->getRepository('SkobkinPointToolsBundle:User')->createQueryBuilder('u');
$subscribers = $qb
->select('u')
->innerJoin('u.subscriptions', 's')
->where('s.author = :author')
->setParameter('author', $user->getId())
->getQuery()->getResult()
;
$qb = $this->getDoctrine()->getManager()->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->createQueryBuilder('se'); $qb = $this->getDoctrine()->getManager()->getRepository('SkobkinPointToolsBundle:SubscriptionEvent')->createQueryBuilder('se');
$subscriptionsEvents = $qb $subscriptionsEvents = $qb
->select() ->select()
->where('se.author = :author') ->where('se.author = :author')
->orderBy('se.date', 'desc') ->orderBy('se.date', 'desc')
->setMaxResults(30) ->setMaxResults(10)
->setParameter('author', $user) ->setParameter('author', $user)
->getQuery()->getResult() ->getQuery()->getResult()
; ;
return $this->render('SkobkinPointToolsBundle:User:show.html.twig', [ return $this->render('SkobkinPointToolsBundle:User:show.html.twig', [
'user' => $user, 'user' => $user,
'subscribers' => $subscribers,
'log' => $subscriptionsEvents, 'log' => $subscriptionsEvents,
'avatar_url' => $userApi->getAvatarUrl($user, UserApi::AVATAR_SIZE_LARGE), 'avatar_url' => $userApi->getAvatarUrl($user, UserApi::AVATAR_SIZE_LARGE),
]); ]);
@ -44,8 +56,20 @@ class UserController extends Controller
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
/** @var QueryBuilder $qb */ /** @var QueryBuilder $qb */
$qb = $em->getRepository('SkobkinPointToolsBundle:Subscription')->createQueryBuilder('us'); $qb = $em->getRepository('SkobkinPointToolsBundle:Subscription')->createQueryBuilder('s');
/** @var TopUserDTO[] $topUsers */
$topUsers = $qb
->select(['COUNT(s.subscriber) as cnt', 'NEW SkobkinPointToolsBundle:TopUserDTO(a.login, COUNT(s.subscriber))'])
->innerJoin('s.author', 'a')
->orderBy('cnt', 'desc')
->groupBy('a.id')
->setMaxResults(30)
->getQuery()->getResult()
;
return $this->render('@SkobkinPointTools/User/top.html.twig', [
'top_users' => $topUsers
]);
} }
} }

View file

@ -0,0 +1,25 @@
<?php
namespace Skobkin\Bundle\PointToolsBundle\Entity;
/**
* Data Transfer Object for top users list
*/
class TopUserDTO
{
/**
* @var string
*/
public $login;
/**
* @var int
*/
public $subscribersCount;
public function __construct($login, $subscribersCount)
{
$this->login = $login;
$this->subscribersCount = $subscribersCount;
}
}

View file

@ -21,8 +21,8 @@
<div id="collapse-subscribers" class="panel-collapse collapse in"> <div id="collapse-subscribers" class="panel-collapse collapse in">
<div class="panel-body"> <div class="panel-body">
<ul class="users mosaic"> <ul class="users mosaic">
{% for sub in user.subscribers %} {% for user in subscribers %}
<li><a href="{{ url('user_show', {login: sub.subscriber.login}) }}">@{{ sub.subscriber.login }}</a></li> <li><a href="{{ url('user_show', {login: user.login}) }}">@{{ user.login }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>

View file

@ -0,0 +1,24 @@
{% extends "::base.html.twig" %}
{% block header_title %}Top @ Point Tools{% endblock %}
{% block content %}
<h1>{{ 'Top users'|trans }}</h1>
<table class="table table-striped">
<thead>
<tr>
<td>{{ 'User'|trans }}</td>
<td>{{ 'Subscribers count'|trans }}</td>
</tr>
</thead>
<tbody>
{% for user in top_users %}
<tr>
<td><a href="{{ url('user_show', {login: user.login}) }}">@{{ user.login }}</a></td>
<td>{{ user.subscribersCount }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}