I'm setting up a Symfony project displaying paginated blogposts with an admin interface to manage all this stuff. On this admin it is also possible to "highlight" one of those public blogposts so that this highlighted one is displayed at first position only on the first page.
I need the same item count on each page and that is the problem I'm dealing with.
I'm using PagerFanta so I created an AbstractRepository with a "paginate" function.
protected function paginate(QueryBuilder $qb, $limit = 20, $offset = 0)
{
if ($limit == 0) {
throw new \LogicException('$limit must be greater than 0.');
}
//Instantiates the pagination object with the result of the query
$pager = new Pagerfanta(new DoctrineORMAdapter($qb));
//Sets max data per page
$pager->setMaxPerPage($limit);
//Sets the current page
$pager->setCurrentPage($offset);
return $pager;
}
In my blogpost repository I made a querybuilder to get all public blogpost excluding the highlighted one because I can get it in another way to display it on top of the first page.
public function findAllVisible($id, $limit = 3, $offset = 1, $order = 'DESC')
{
$qb = $this
->createQueryBuilder('a')
->select('a')
->where('a.website = :website')
->setParameter('website', 'blog')
->andWhere('a.public = :public')
->setParameter('public', true)
->andWhere('a.id != :id')
->setParameter('id', $id)
->orderBy('a.dateInsert', $order)
;
return $this->paginate($qb, $limit, $offset);
}
So I first tried to change the limit and the offset according to the current page but I logically lost one item between the first and the second page.
Then I tried to include the highlighted blogpost in querybuilder but I don't know how to define it as the first result if the current page is the first one.
Any idea of how to force the first result to be the highlighted blogpost only on first page? Or another clean and appropriate way to display results as expected?
I answer to myself because I managed to do what I needed to. In case of someone is dealing with the same issue, here is how I did.
I don't use PagerFanta anymore but Doctrine Paginator tool.
Instead of excluding my highlighted article from my query I replaced my initial ORDER BY by a.id = :highlightedId DESC, a.dateInsert DESC.
Now it's working as expected.
Here is my new repository function:
/**
* Finds all visible articles
*
* #param int $highlightedTipId the highlighted tip id
* #param int $page current page
* #param int $limit max items per page
*
* #throws InvalidArgumentException
* #throws NotFoundHttpException
*
* #return Paginator
*/
public function findAllVisible($highlightedTipId, $limit = 3, $page)
{
if (!is_numeric($page)) {
throw new InvalidArgumentException('$page value is incorrect (' . $page . ').');
}
if ($page < 1) {
throw new NotFoundHttpException('Page not found');
}
if (!is_numeric($limit)) {
throw new InvalidArgumentException('$limit value is incorrect (' . $limit . ').');
}
$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery(
"SELECT
a,
CASE WHEN a.id = :id THEN 1 ELSE 0 END AS HIDDEN sortCondition
FROM App\Entity\Item a
WHERE
a INSTANCE OF App\Entity\TipArticle
AND
a.website = :website
AND
a.public = :public
ORDER BY
sortCondition DESC,
a.dateInsert DESC
"
);
$query->setParameter(':website', 'blog');
$query->setParameter(':public', true);
$query->setParameter(':id', $highlightedTipId);
$firstResult = ($page - 1) * $limit;
$query
->setFirstResult($firstResult)
->setMaxResults($limit);
$paginator = new Paginator($query);
if (($paginator->count() <= $firstResult) && $page != 1) {
throw new NotFoundHttpException('Page not found');
}
return $paginator;
}
A word about this line CASE WHEN a.id = :id THEN 1 ELSE 0 END AS HIDDEN sortCondition: it is the only way I found to do a ORDER BY a.id = :highlightedId DESC with Doctrine. As you can see I made a DQL but I is also possible with QueryBuilder.
Hope it will help! :)
Nice, well done. If I may offer some advice though. In a repo you shouldn't need to get the ObjectManager ($this->getEntityManager()) as the repo is already for a type of Entity, Item in this case. You should use Criteria instead. practical example docs
You should have the ObjectManager in whichever controller you've got, so then you'd do:
$items = $this-getObjectManager()->getRepository(Item::class)->findAllVisible($params)
For use of the Paginator you should use the QueryBuilder, with Expressions, like here
As a practical example, an indexAction of mine:
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator as OrmPaginator;
use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator as OrmAdapter;
use Zend\Paginator\Paginator;
public function indexAction()
{
// get current page, defaults to 1
$page = $this->params()->fromQuery('page', 1);
// get current page size, defaults to 10
$pageSize = $this->params()->fromQuery('pageSize', 10);
// get ordering, defaults to 'createdAt'
$orderBy = $this->params()->fromQuery('orderBy', 'createdAt');
// get order direction, defaults to Criteria::DESC
$orderDirection = ($this->params()->fromQuery('orderDirection') === Criteria::ASC)
? Criteria::ASC
: Criteria::DESC;
$criteria = new Criteria();
$criteria->setFirstResult($page * $pageSize);
$criteria->setMaxResults($pageSize);
$criteria->orderBy([$orderBy => $orderDirection]);
/** #var QueryBuilder $queryBuilder */
$queryBuilder = $this->getObjectManager()->createQueryBuilder();
$queryBuilder->select('a')->from(Article::class, 'a');
$queryBuilder->addCriteria($criteria);
$paginator = new Paginator(new OrmAdapter(new OrmPaginator($queryBuilder)));
$paginator->setCurrentPageNumber($page); // set current page
$paginator->setItemCountPerPage($pageSize); // set item count per page
return [
'paginator' => $paginator,
'queryParams' => $this->params()->fromQuery(), // pass these for your pagination uri's
];
}
NOTE: In the above the $this is an instance of a Zend Framework controller, where ->fromQuery returns (if present) a given key from the Query bit if a URI, else return the 2nd param default (or null). You should do something similar.
Related
I'm using a search code and pagination code in my controller(s), it goes without saying it's bad coding habits by repeating code. That being said what is the best practice in Symfony2, to avoid repeating code in all my controllers?
And how do I access the code once it's been re-factored?
Controller
// Search code
$results = null;
$query = $request->query->get('q');
if (!empty($query)) {
$em = $this->getDoctrine()->getManager();
$results = $em->createQueryBuilder()
->from('AcmeDemoBundle:Blog', 'b')
->select('b')
->where('b.title LIKE :search')
->setParameter(':search', "%${query}%")
->getQuery()
->getResult();
}
// Pagination code
$page = $request->get('page');
$count_per_page = 5;
$total_count = $this->getTotalBlogs();
$total_pages = ceil($total_count/$count_per_page);
if (!is_numeric($page)) {
$page = 1;
} else {
$page = floor($page);
}
if ($total_count <= $count_per_page) {
$page = 1;
}
if (($page * $count_per_page) > $total_count) {
$page = $total_pages;
}
$offset = 0;
if ($page > 1) {
$offset = $count_per_page * ($page - 1);
}
$em = $this->getDoctrine()->getManager();
$blogQuery = $em->createQueryBuilder()
->select('b')
->from('AcmeDemoBundle:Blog', 'b')
->addOrderBy('b.created', 'DESC')
->setFirstResult($offset)
->setMaxResults($count_per_page);
$blogFinalQuery = $blogQuery->getQuery();
$blogPage = $blogFinalQuery->getArrayResult();
foreach ($blogPage as $blog) {
$blog_id = $blog['id'];
$commentRepository = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Comment');
$comments[] = $commentRepository->findByBlog($blog_id);
}
// exit(\Doctrine\Common\Util\Debug::dump($comments));
return $this->render('AcmeDemoBundlBundle:Default:index.html.twig', array(
'blogPage' => $blogPage,
'total_pages' => $total_pages,
'current_page' => $page,
'comments' => $comments,
'query' => $query,
'results' => $results,
));
For a start, you can put all your custom queries in custom repository classes. I suspect that would cover all the re-use you need in this case.
For example, create a BlogRepository class in AcmeDemoBundle:Repository and annotate the Blog entity class as follows to define it's repository class:
/**
* #ORM\Entity(repositoryClass="Acme\DemoBundle\Repository\BlogRepository")
*/
Then add methods to the repository for each custom query that's needed, bearing in mind the way that repository methods are typically named. It looks as though the controller method getTotalBlogs() could also be a method on BogRepository e.g.:
public function findFiltered($page, $count_per_page = 5, $filterText = '')
{
$total_count = $this->findTotal();
// Code to initialise page and offset here
$queryBuilder = $this->createQueryBuilder('blog');
$queryBuilder->...
...
}
Note that the above method could be used to get all the blogs if no $filterText is passed in. You would just need something like this:
if (!empty($filterText))
{
queryBuilder->where('b.title LIKE :search')
->setParameter(':search', "%${query}%")
}
Then, a CommentRepository could be created with a method to find all the comments for a given set of blog(id)s. Note you could use a sql 'IN' clause to get all the comments using a single query:
$commentQuery = $em->createQueryBuilder()
->select('comment')
->from('AcmeDemoBundle:Comment', 'comment')
->where('comment.blog IN (:ids)')
->setParameter('ids', $blogIds);
In addition to custom repository classes I use manager services (e.g. BlogManager) to encapsulate business processes. My controllers mainly use the managers rather than using the repositories directly but it depends on the functionality.
I'm a little confused that you have an overall results query which only returns Blogs where the title is like the search text whilst the paged query returns (a page of) all blogs. That may just be a because your code is in progress?
I have a simple query which selects entities and uses limit statement. I am using Doctrine NativeQuery because I have FIELD() function in sql query, and I need a collection of objects as a result.
That query works.
However I need also a total number of records, so I use SQL_CALC_FOUND_ROWS in the first query. After the first gets the result I create another ResultSetMapping, another $nativeQuery, execute SELECT FOUND_ROWS() AS found_rows and I keep getting total number of '1'.
$rsm = new ResultSetMapping();
$rsm->addEntityResult('\\MyCompany\\Administration\\Domain\\Model\\Applicant\\Applicant', 'a');
$rsm->addFieldResult('a', 'first_name', 'firstName');
$rsm->addFieldResult('a', 'last_name', 'lastName');
$query = $this->em->createNativeQuery('SELECT SQL_CALC_FOUND_ROWS * FROM recruitment_applicant ORDER BY FIELD(id,5,15,8,17,2,1,16,9,7,11,6,10,12,13,14,18)', $rsm);
$result = $query->getResult(); // this result is ok
$sqlCountRows = "SELECT FOUND_ROWS() AS found_rows";
$countRowsRsm = new ResultSetMapping();
$countRowsRsm->addScalarResult('found_rows', 'foundRows');
$countRowsQuery = $this->em->createNativeQuery($sqlCountRows,$countRowsRsm);
$rowsCount = $countRowsQuery->getResult();
$total = $rowsCount[0]['foundRows']; // result is '1' when it should be '16'
I used this example.
You don't have to use native query. FIELD() is really very easy to implement as a custom DQL function:
Read DQL User Defined Functions and How to Register Custom DQL Functions on Doctrine/Symfony documentation.
FIELD() implementation:
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class Field extends FunctionNode
{
private $field = null;
private $values = array();
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->arithmeticPrimary();
while (count($this->values) < 1 || $parser->getLexer()->lookahead['type'] !== Lexer::T_CLOSE_PARENTHESIS) {
$parser->match(Lexer::T_COMMA);
$this->values[] = $parser->arithmeticPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(SqlWalker $sqlWalker)
{
$values = array();
foreach ($this->values as $value) {
$values[] = $value->dispatch($sqlWalker);
}
return sprintf('FIELD(%s, %s)', $this->field->dispatch($sqlWalker), implode(', ', $values));
}
}
You won't event need a count query. However, if you'd need COUNT(*) query you can easily clone your original query and use CountWalker to create count query from select query.
I found out what might be a cause of the problem: Symfony2 profiler, queries section, shows total of 22 queries executed. My first query gets run third in a row and my second query, the one to return the number of rows gets executed 13th.
SQL_CALC_FOUND_ROWS works if SELECT FOUND_ROWS() is run immediately after the first query.
I have a one to many relationship where one page has many versions.
**page**
id
parent_id
**page_version**
id
page_id
title
published
date
These are related by the foreign key page_id. So I have a Page entity and a PageVersion entity:
class Page
{
/**
* #ORM\OneToMany(targetEntity="PageVersion", mappedBy="page")
*/
private $pageversions;
}
class PageVersion
{
/**
* #var page
*
* #ORM\ManyToOne(targetEntity="Page", inversedBy="pageversions")
*
*/
private $page;
}
So I can get all page versions for each page. However, each page will only ever have one published page version. Therefore, when querying how can I get the latest version? I.e Where published = '1' rather than getting a list of all versions?
Here is an example of my query:
public function findAllPages()
{
$query = $this->getEntityManager()
->createQuery('
SELECT DISTINCT p,v
FROM XYZWebsiteBundle:Page p
JOIN p.pageversions v
WHERE v.published = :published
AND v.deleted = :deleted'
)->setParameters(array('published' => 1, 'deleted' => 0));
try {
return $query->getResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
However if I loop through the result I can only access the Page properties and not PageVersion properties e.g title, published, date etc.
$entities = $em->getRepository('XYZWebsiteBundle:Page')->findAllPages();
foreach($entities as $entity){
print($entity->getPageVersion()->getTitle());
}
The error returned is Fatal error: Call to undefined method Doctrine\ORM\PersistentCollection::getTitle().
$er = $this->getDoctrine()->getRepository('XYZWebsiteBundle:Page');
$qb = $er->createQueryBuilder('p')
->where('p.published = :published')
->setParameter('published', 1)
;
$entities=$qb->getQuery()->getResult();
If you are sure there will never be no more than 1 page with the published status, you can even use getOneOrNullResult() instead of getResult(). This returns null if there is no matching entity, the entity if there is one matching, and an exception if there is more than one.
Edit: ok, so you have to build the query on PageVersion rather than page then. Try:
$er = $this->getDoctrine()->getRepository('XYZWebsiteBundle:PageVersion');
$qb = $er->createQueryBuilder('p')
->where('p.page = :page')
->setParameter('page', $page)
->andWhere('p.published = :published')
->setParameter('published', 1)
;
$pageVersion=$qb->getQuery()->getResult();
with $page being the page you are trying to find the published version for.
Ok so here's the issue.
I have a Entity named HelpDocuments and an Entity named LogEntry.
HelpDocuments can be dismissed by the user. When this happens I create a LogEntry with the following attributes:
event - eg: helpDocument.dismiss
entity_id - eg: 11
entityDiscriminator - eg: HelpDocument
There are no relationships created between HelpDocument and LogEntry as I'm implementing my own discriminator logic.
So what I'm trying to achieve is query for all HelpDocuments that have not been dismissed. I can do that with sql, left outer subquery join like so:
SELECT HelpDocument.*, temp.*
FROM HelpDocument
LEFT OUTER JOIN(
SELECT LogEntry.entity_id
FROM LogEntry
WHERE LogEntry.entityDiscriminator = 'HelpDocument'
AND LogEntry.event = 'helpDocument.dismiss'
AND LogEntry.entity_id = 11
) as temp ON HelpDocument.id = temp.entity_id
WHERE temp.entity_id IS NULL;
My issue is how do I turn this into DQL given that there is no relationship defined?
Updated Solution:
So the solution was to not use an LEFT OUTER JOIN because they don't exist / make sense in Doctrine2. In the end I had to do a subquery join:
/**
* Filter by User Dismissed
*
* #param $qb
* #param $route
* #return mixed
*/
public function filterQueryByUserDismissed(QueryBuilder $qb, $args)
{
$args = array_merge(array(
"user" => null,
"dismissed" => false
), $args);
/** #var $dismissedQB QueryBuilder */
$dismissedQB = $this->_em->createQueryBuilder();
/*
This line is important. We select an alternative attribute rather than
letting Doctrine select le.id
*/
$dismissedQB->select('le.entityId')
->from('\Mlf\AppBundle\Entity\UserEntityEventLog', 'le')
->where('le.entityDiscriminator = :entityDiscriminator')
->andWhere('le.event = :event')
->andWhere('le.user = :userId');
$function = (true === $args['dismissed']) ? "in" : "notIn";
$expr = $qb->expr()->$function($this->classAlias.'.id', $dismissedQB->getDQL());
/** #var $qb QueryBuilder */
$qb->andWhere($expr)
->setParameter("entityDiscriminator", HelpDocument::getDiscriminator())
->setParameter("event", HelpDocumentEvents::HELPDOCUMENT_DISMISS)
->setParameter("userId", $args["user"]);
// exit($result = $qb->getQuery()->getSQL());
return $qb;
}
This DQL query results in the following SQL:
SELECT h0_.id AS id0
FROM HelpDocument h0_
WHERE (
h0_.id NOT IN (
SELECT l1_.entity_id
FROM LogEntry l1_
WHERE l1_.entityDiscriminator = 'helpDocument'
AND l1_.event = 'helpDocument.dismiss'
AND l1_.user_id = 1
)
)
Yay!
I saw your solution and I have a minor change that will be a huge performance improvement. Especially if you have more then a couple of thousand rows.
public function filterQueryByUserDismissed(QueryBuilder $qb, $args)
{
$args = array_merge(array(
"user" => null,
"dismissed" => false
), $args);
/** #var $dismissedQB QueryBuilder */
$dismissedQB = $this->_em->createQueryBuilder();
/*
This line is important. We select an alternative attribute rather than
letting Doctrine select le.id
*/
$dismissedQB->select('le.entityId')
->from('\Mlf\AppBundle\Entity\UserEntityEventLog', 'le')
->where('le.entityDiscriminator = :entityDiscriminator')
->andWhere('le.event = :event')
->andWhere('le.user = :userId');
// ---- My changes below
// Get an array with the ids
$dismissedIdsMap = $dismissedQB->getQuery()->getResults();
$dismissedIds = array_map(
function($a){
return $a['entityId'];
},
$dismissedIdsMap);
$function = (true === $args['dismissed']) ? "in" : "notIn";
$expr = $qb->expr()->$function($this->classAlias.'.id', $dismissedIds);
// ---- My changes above
/** #var $qb QueryBuilder */
$qb->andWhere($expr)
->setParameter("entityDiscriminator", HelpDocument::getDiscriminator())
->setParameter("event", HelpDocumentEvents::HELPDOCUMENT_DISMISS)
->setParameter("userId", $args["user"]);
// exit($result = $qb->getQuery()->getSQL());
return $qb;
}
The code above is using two queries. If you are using one query, MySQL will create a temporary view from your subquery and then query the view with master query. It is a lot of overhead creating this view. With two queries you will be keeping the "view" in the PHP memory and this will reduce the overhead dramatically.
I'm using Doctrine's QueryBuilder to build a query, and I want to get the total count of results from the query.
$repository = $em->getRepository('FooBundle:Foo');
$qb = $repository->createQueryBuilder('n')
->where('n.bar = :bar')
->setParameter('bar', $bar);
$query = $qb->getQuery();
//this doesn't work
$totalrows = $query->getResult()->count();
I just want to run a count on this query to get the total rows, but not return the actual results. (After this count query, I'm going to further modify the query with maxResults for pagination.)
Something like:
$qb = $entityManager->createQueryBuilder();
$qb->select('count(account.id)');
$qb->from('ZaysoCoreBundle:Account','account');
$count = $qb->getQuery()->getSingleScalarResult();
Some folks feel that expressions are somehow better than just using straight DQL. One even went so far as to edit a four year old answer. I rolled his edit back. Go figure.
Here is another way to format the query:
return $repository->createQueryBuilder('u')
->select('count(u.id)')
->getQuery()
->getSingleScalarResult();
It's better to move all logic of working with database to repositores.
So in controller you write
/* you can also inject "FooRepository $repository" using autowire */
$repository = $this->getDoctrine()->getRepository(Foo::class);
$count = $repository->count();
And in Repository/FooRepository.php
public function count()
{
$qb = $repository->createQueryBuilder('t');
return $qb
->select('count(t.id)')
->getQuery()
->getSingleScalarResult();
}
It's better to move $qb = ... to separate row in case you want to make complex expressions like
public function count()
{
$qb = $repository->createQueryBuilder('t');
return $qb
->select('count(t.id)')
->where($qb->expr()->isNotNull('t.fieldName'))
->andWhere($qb->expr()->orX(
$qb->expr()->in('t.fieldName2', 0),
$qb->expr()->isNull('t.fieldName2')
))
->getQuery()
->getSingleScalarResult();
}
Also think about caching your query result - http://symfony.com/doc/current/reference/configuration/doctrine.html#caching-drivers
public function count()
{
$qb = $repository->createQueryBuilder('t');
return $qb
->select('count(t.id)')
->getQuery()
->useQueryCache(true)
->useResultCache(true, 3600)
->getSingleScalarResult();
}
In some simple cases using EXTRA_LAZY entity relations is good
http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html
If you need to count a more complex query, with groupBy, having etc... You can borrow from Doctrine\ORM\Tools\Pagination\Paginator:
$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query);
$totalRows = count($paginator);
Since Doctrine 2.6 it is possible to use count() method directly from EntityRepository. For details see the link.
https://github.com/doctrine/doctrine2/blob/77e3e5c96c1beec7b28443c5b59145eeadbc0baf/lib/Doctrine/ORM/EntityRepository.php#L161
Example working with grouping, union and stuff.
Problem:
$qb = $em->createQueryBuilder()
->select('m.id', 'rm.id')
->from('Model', 'm')
->join('m.relatedModels', 'rm')
->groupBy('m.id');
For this to work possible solution is to use custom hydrator and this weird thing
called 'CUSTOM OUTPUT WALKER HINT':
class CountHydrator extends AbstractHydrator
{
const NAME = 'count_hydrator';
const FIELD = 'count';
/**
* {#inheritDoc}
*/
protected function hydrateAllData()
{
return (int)$this->_stmt->fetchColumn(0);
}
}
class CountSqlWalker extends SqlWalker
{
/**
* {#inheritDoc}
*/
public function walkSelectStatement(AST\SelectStatement $AST)
{
return sprintf("SELECT COUNT(*) AS %s FROM (%s) AS t", CountHydrator::FIELD, parent::walkSelectStatement($AST));
}
}
$doctrineConfig->addCustomHydrationMode(CountHydrator::NAME, CountHydrator::class);
// $qb from example above
$countQuery = clone $qb->getQuery();
// Doctrine bug ? Doesn't make a deep copy... (as of "doctrine/orm": "2.4.6")
$countQuery->setParameters($this->getQuery()->getParameters());
// set custom 'hint' stuff
$countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, CountSqlWalker::class);
$count = $countQuery->getResult(CountHydrator::NAME);
For people who are using only Doctrine DBAL and not the Doctrine ORM, they will not be able to access the getQuery() method because it doesn't exists. They need to do something like the following.
$qb = new QueryBuilder($conn);
$count = $qb->select("count(id)")->from($tableName)->execute()->fetchColumn(0);
To count items after some number of items (offset), $qb->setFirstResults() cannot be applied in this case, as it works not as a condition of query, but as an offset of query result for a range of items selected (i. e. setFirstResult cannot be used togather with COUNT at all). So to count items, which are left I simply did the following:
//in repository class:
$count = $qb->select('count(p.id)')
->from('Products', 'p')
->getQuery()
->getSingleScalarResult();
return $count;
//in controller class:
$count = $this->em->getRepository('RepositoryBundle')->...
return $count-$offset;
Anybody knows more clean way to do it?
Adding the following method to your repository should allow you to call $repo->getCourseCount() from your Controller.
/**
* #return array
*/
public function getCourseCount()
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('count(course.id)')
->from('CRMPicco\Component\Course\Model\Course', 'course')
;
$query = $qb->getQuery();
return $query->getSingleScalarResult();
}
You can also get the number of data by using the count function.
$query = $this->dm->createQueryBuilder('AppBundle:Items')
->field('isDeleted')->equals(false)
->getQuery()->count();