Doctrine and Symfony2: WHERE a.title LIKE $array - php

Hey I'm writing this post because I have few problem passing an array value in the doctrine query.
Here is the entire query as it is:
$data = $request->request->all();
$dql = "SELECT a FROM PfBlogBundle:Article a WHERE a.title LIKE '{$data['search']}' ORDER by a.id DESC";
If I print_r($data) I get the value so it's there somewhere. I just don't understand why it's not passing in the query.. Was expecting LIKE '{$data['search']}' to work but it doesn't.

From what I can tell by your snippet, you're looking for something like this:
$entityManager->getRepository('PfBlogBundle:Article')
->findBy(
array(
'key' => 'value'
)
);
Where key is the property/field and the value is the value to look for. Check the Symfony manual page. The bit you're after is Fetching Objects from the Database.
To use a like in the where clause, refer to this SO question, on how to use setParameter. You'll get your query with this:
$repo = $entityManager->getRepository('PfBlogBundle:Article');
$query = $repo->createQueryBuilder('a')
->where('a.title LIKE :title')
->setParameter('title', '%'.$data['search'].'%')
->getQuery();
Of course, add wildcards to suite your needs. I've enclosed the $data['search'] value in two % wildcards, which is slow, but then again: I don't know what you're actually doing. It might be that all you're after is the case-insensitive nature of LIKE, in which case the % can be left out all together...
Based on your previous questions (BTW: consider accepting an answer once in a while):
public function searchAction(Request $request)
{
$data = $request->get->all();
$repo = $this->getDoctrine()
->getRepository('PfBlogBundle:Article');
$query = $repo->createQueryBuilder('a')
->where('a.title LIKE :title')
->setParameter('title', '%'.$data['search'].'%')
->getQuery();
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query->getResults(),//get the results here
$this->requrest->get('page',1),
4
);
return $this->render('PfBlogBundle:Default:blog.html.twig', array('pagination'=>$pagination));
}
But this is just a crude fix, Google doctrine-symfony pagination, there are many detailed blog-posts on the matter

Related

yii\db\Query::limit() function not limiting the records - Yii2

Below is the code I'm using to get data from my table(s) for creating REST api.
$query = new yii\db\Query();
$sql = $query
->select('a.vehicle_number, b.device_id, b.dated, b.speed, b.ignition, b.latitude, b.longitude')
->from('tk103_devices a, tk103_current_location b')
->where('a.device_id = b.device_id AND a.transporter_id='.$id)
->orderBy(['a.vehicle_number'=>SORT_ASC])
->limit(1);
$dataProvider = new ActiveDataProvider([
'query'=>$sql
]);
return array('count_flag'=>$countFlag, 'dataProvider'=>$dataProvider->getModels());
I had set the limit(1) which does "Sets the LIMIT part of the query." as per Yii official doc http://www.yiiframework.com/doc-2.0/yii-db-querytrait.html#limit()-detail.
When I am executing the above query, all the records are being returned by the dataprovider.
What's wrong with my code?
ActiveDataProvider does not take care at query limit.
http://www.yiiframework.com/doc-2.0/guide-output-data-providers.html#active-data-provider
Extract from above link:
Note: If a query already specifies the orderBy clause, the new
ordering instructions given by end users (through the sort
configuration) will be appended to the existing orderBy clause. Any
existing limit and offset clauses will be overwritten by the
pagination request from end users (through the pagination
configuration).
So, since you have fixed data, use ArrayDataProvider:
$data = $query
->select('a.vehicle_number, b.device_id, b.dated, b.speed, b.ignition, b.latitude, b.longitude')
->from('tk103_devices a, tk103_current_location b')
->where('a.device_id = b.device_id AND a.transporter_id='.$id)
->orderBy(['a.vehicle_number'=>SORT_ASC])
->limit(1)
->all();
$dataProvider = new \yii\data\ArrayDataProvider(['allModels' => $data]);
Did some homework by myself, I find solution to the above problem by changing the code as below:
$query = new yii\db\Query();
$sql = $query
->select('a.vehicle_number, b.device_id, b.dated, b.speed, b.ignition, b.latitude, b.longitude')
->from('tk103_devices a, tk103_current_location b')
->where('a.device_id = b.device_id AND a.transporter_id='.$id)
->orderBy(['a.vehicle_number'=>SORT_ASC])
->one();
$dataProvider = new ActiveDataProvider([
'query'=>$sql
]);
return array('count_flag'=>$countFlag, 'dataProvider'=>$dataProvider);
As per my scenario, I wanted to retrieve only first record. So, I used one() instead of limit(1).
Secondly, I was returning dataProvider as $dataProvider->getModels(). I changed this to $dataProvider only. Since "ActiveDataProvider does not take care at query limit." as per Fabrizio Caldarelli's answer below (or) above, it was returning all retrieved records.
Hope that helps someone having related issues.
For previous code to work, you must see Fabrizio Caldarelli's answer below (or) above.

How to print single value of entity without dumping the whole object?

I want to get one single value from entity.Can anyone help me here.
Here is my code.Please let me know what is missing here.
$query = $em->createQuery("SELECT e FROM AdminBundle:MailTemplates e WHERE e.keyword = '" .$keywordVal."'");
$query->execute();
$result = $query->getResult();
echo $result ->getId();
Here i want the 'id'.
This is noted in the documentation how you can do this.
So given you're code this will become:
$query = $em->createQuery("SELECT e.id FROM AdminBundle:MailTemplates e WHERE e.keyword = ?1");
$query->setParameter(1, $keywordVal);
$query->execute();
$result = $query->getResult(); // array of MailTemplates ids
Note: I also made use of setParameters instead of setting the value directly in the query.
In your controller:
$this->get('database_connection')->fetchColumn('select id from mail_templates where...');
That's much better for performance and much easier if you don't want to have a deal with query builder and other doctrine orm stuff.
Using the query builder you could do...
$queryBuilder = $em->createQueryBuilder('e');
$queryBuilder
->select('e.yourColumn')
// This will return just this column
// Alternatively you could omit any select to return the whole object
// that you could then use like $object->getYourColumn() if you so chose
->where($queryBuilder->expr()->eq('e.keyword', ':keyword'))
->setParameter('keyword', $keyword)
;
return $queryBuilder
->getQuery()
->getResult();
try this on loading Entities instead of creating own queries
Loading the entity with the Repository.
$rep = $this->getDoctrine()->getManager()->getRepository("Bundlename:Entity");
//find one by keyword -> single entity
$entity = $rep->findOneBy(array('keyword' => $keyword));
//find all by keyword - Array of entities
$result = $rep->findBy(array('keyword' => $keyword));

Eloquent ORM: count() remove the select(...)

I am using Eloquent ORM outside of Laravel-4 and I am building a custom Paginator.
First, I build a query using Fluent Query Builder. I want to get the number of result the query could return using count() and then I do a custom pagination using take(x) and skip(y). I need to do the count() before the take()->skip()->get() so I dont fall outside of the page range. The problem is that when I use the count() method on the query, it seems to remove any select I added previously.
I isolated the problem to this simple example:
$query = DB::table('companies')
->join('countries','companies.country_id','=','countries.id')
->select(
'companies.name as company_name',
'countries.name as country_name'
);
$nbPages = $query->count();
$results = $query->get();
//$results contains all fields of both tables 'companies' and 'countries'
If i invert the order of the count and get, it works fine:
$results = $query->get();
$nbPages = $query->count();
//$results contains only 'company_name' and 'country_name'
Question: is there a more elegant way the using something like this:
$tmp = clone $query;
$nbPages = $tmp->count();
$results = $query->get();
There is not, unfortunately. Open issue on github about the problem: https://github.com/laravel/framework/pull/3416

How to use a findBy method with comparative criteria

I'd need to use a "magic finder" findBy method using comparative criteria (not only exact criteria). In other words, I need to do something like this:
$result = $purchases_repository->findBy(array("prize" => ">200"));
so that I'd get all purchases where the prize is above 200.
The class Doctrine\ORM\EntityRepository implements Doctrine\Common\Collections\Selectable API.
The Selectable interface is very flexible and quite new, but it will allow you to handle comparisons and more complex criteria easily on both repositories and single collections of items, regardless if in ORM or ODM or completely separate problems.
This would be a comparison criteria as you just requested as in Doctrine ORM 2.3.2:
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where(\Doctrine\Common\Collections\Criteria::expr()->gt('prize', 200));
$result = $entityRepository->matching($criteria);
The major advantage in this API is that you are implementing some sort of strategy pattern here, and it works with repositories, collections, lazy collections and everywhere the Selectable API is implemented.
This allows you to get rid of dozens of special methods you wrote for your repositories (like findOneBySomethingWithParticularRule), and instead focus on writing your own criteria classes, each representing one of these particular filters.
This is an example using the Expr() Class - I needed this too some days ago and it took me some time to find out what is the exact syntax and way of usage:
/**
* fetches Products that are more expansive than the given price
*
* #param int $price
* #return array
*/
public function findProductsExpensiveThan($price)
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$q = $qb->select(array('p'))
->from('YourProductBundle:Product', 'p')
->where(
$qb->expr()->gt('p.price', $price)
)
->orderBy('p.price', 'DESC')
->getQuery();
return $q->getResult();
}
You have to use either DQL or the QueryBuilder. E.g. in your Purchase-EntityRepository you could do something like this:
$q = $this->createQueryBuilder('p')
->where('p.prize > :purchasePrize')
->setParameter('purchasePrize', 200)
->getQuery();
$q->getResult();
For even more complex scenarios take a look at the Expr() class.
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($criteria->expr()->gt('id', 'id'))
->setMaxResults(1)
->orderBy(array("id" => $criteria::DESC));
$results = $articlesRepo->matching($criteria);
The Symfony documentation now explicitly shows how to do this:
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Product p
WHERE p.price > :price
ORDER BY p.price ASC'
)->setParameter('price', '19.99');
$products = $query->getResult();
From http://symfony.com/doc/2.8/book/doctrine.html#querying-for-objects-with-dql
I like to use such static methods:
$result = $purchases_repository->matching(
Criteria::create()->where(
Criteria::expr()->gt('prize', 200)
)
);
Of course, you can push logic when it is 1 condition, but when you have more conditions it is better to divide it into fragments, configure and pass it to the method:
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->where($expr->gt('prize', 200));
$criteria->orderBy(['prize' => Criteria::DESC]);
$result = $purchases_repository->matching($criteria);
Copying the findBy query and modifying it to return your expected result is a good approach.

Symfony 2 finding blog posts for multiple users

I have 3 tables: user, user_followers and blog_posts.
Users can follow other users and users are related to blog_post by user_id.
I need to get all blog posts that people I follow have written.
I tried something like:
$followedUsers = $user->getFollowedByMe(); //This one works
$posts = $entityManager->getRepository('<BundleHere>:BlogPosts')
->findBy(array('user_id' => $followedUsers));
And I tried a lot more variations but can't figure it out. Maybe someone knows a better way to search by multiple objects not just one.
You can use this kind of code in your BlogRepository.php in example.
public function getBlogPost($userId)
{
return $this
->_em
->createQueryBuilder('p')
->leftJoin('p.user', 'u')
->where('u.id = :id')
->setParameter('id', $userId)
->getQuery()
->getResult();
}
createQueryBuilder('p') will automatically create the select and from (select entity (post ?) from table).
Then, you can use it like this :
$posts = $entityManager->getRepository('<BundleHere>:BlogPosts')->getBlogPost($userId);
I can't give you the exact query because we don't have enough informations about your entities. But this way, you can write nice queries to get exactly what you want.
You can do:
$posts = $entityManager->getRepository('<BundleHere>:BlogPosts')
->createQueryBuilder('b')
->whereIn('b.user', $followedUsers)
->getQuery()
->getResult();
'user' should be the name of property used to hold the user in the Blogpost object.
So i figured it out (thanx guys for pointing me in the right direction with queryBuilder).
$followedByMe = $user->getFollowedByMe(); //Getting users i follow
$followedIds = $followedByMe
->map(function( $obj ) { //Using map method to create an array of id's for all followers
return $obj->getId(); //Value to put into array (in this case id)
})->toArray(); //Create an array and assign it to $followedIds variable
$qb = $em->getRepository('<BundleHere>:BlogPosts')->createQueryBuilder('b');
$posts = $qb->where($qb->expr()->in('b.user', $followedIds ))
->orWhere('b.user = :my_id')->setParameter('my_id', $user->getId()) //Get my posts too
->getQuery()
->getResult();

Categories