rails force execution of SQL query in where clause - ruby-on-rails-4

this is the code that i have:
list_views = ListView.where(:user_id => current_user.id)
total_list_views = list_views.size
top_recommended_lists = recommendations_based_on_list_views(list_views, language_score_hash, level_score_hash, category_score_hash)
and then there is this method
def recommendations_based_on_list_views(list_views, language_score_hash, level_score_hash, category_score_hash)
viewed_lists_ids = list_views.map {|list_view| list_view.list_id}.uniq
....
problem is with this code 2 queries are executed on ListView model
one at list_views.size and then at list_views.map {|list_view| list_view.list_id}.uniq
if we can force query execution at ListView.where(:user_id => current_user.id) then only single query to ListView model will be needed OR if any other way
how to achieve this ??

Found the way to this. We can use load:
list_views = ListView.where(:user_id => current_user.id).load
https://apidock.com/rails/ActiveRecord/Relation/load

Related

Symfony : Create a queryBuilder between two entities without mapping

I have two entities (there is no relation between the two entities): A: Relation and B: Post.
I get every post from the current user to display them on the homepage with this request:
public function getPostsCurrentUser($currentUser)
{
$qb = $this->createQueryBuilder('p');
$qb->where('p.member = :member')
->setParameters(['member' => $currentUser])
->orderBy('p.created', 'DESC');
return $qb->getQuery()->getResult();
}
In the example "A: Relation" the user 2 follow the user 1. When a user follow an other user, I would like to also display on the homepage every post of users that the current user are following.
I don't see how to create this request. Can anybody help me ?
Thanks
In the sense of http://sqlfiddle.com/#!9/c5a0bf/2, I would suggest something like the following which uses a subquery to select the ids of all followed users:
class PostRepository {
public function getPostsOfUser($id) {
$query = $this->getEntityManager()->createQuery(
"SELECT p.content
FROM AppBundle:Post p
WHERE p.member = :id
OR p.memberId IN (
SELECT r.friend
FROM AppBundle:Relation r
WHERE r.user = :id
)
ORDER BY p.created DESC"
);
return $query->setParameter('id', $id)
->getResult();
}
}

Doctrine CreateQueryBuilder returns repeated result

In Symfony3 I'm running
php app/console generate:doctrine:entity --entity=AcmeBlogBundle:Post
It creates 2 files: Post (in entity folder) and PostRepository (in repository folder extending \Doctrine\ORM\EntityRepository)
Everything is fine until I try to run the following repository-custom-function in my controller
$rir = $this->getDoctrine()->getRepository("AcmeBlogBundle:Post");
$replacementInstruction = $rir->getOneBy(
array("id" => 6)
);
My custom repository function is as follow
public function getOneBy($option)
{
$alias = "p";
$fields = $this->prepareRequestSelectFields("p");
$qb = $this->createQueryBuilder('Post');
$qb->select($fields)
->from('AcmeBlogBundle:Post', $alias)
->where($alias . '.id = :id')
->setParameter('id', 6)
;
$result = $qb->getQuery()->getResult();
}
private function prepareRequestSelectFields($alias)
{
return $alias. ".id";
}
In my database there are 10 posts with id from 1 to 10, so I expect it to return 1 result, however it return correct Post (id 6) 10 times
Why is that?
p.s. if I move the query builder to a custom service wrapper e.g. PostManager it works just fine (returning 1)
This doesn't really answer my question but apparently createQueryBuilder() in EntityRepository and in EntityManager are different, thanks to https://maltronic.io/2014/12/22/doctrine-createquerybuilder-entitymanager-vs-entityrepository/
So in my EntityRepository it should be
...
$qb = $this->createQueryBuilder('p'); // this should be the alias
$qb->select($fields)
// ->from('AcmeBlogBundle:Post', $alias) // remove this
->where($alias . '.id = :id')
->setParameter('id', 6)
;
...
Personally I dislike how 2 different functions has the same name, but I guess it's fine because one is from Doctrine and one is from Symfony. They are decoupled
edit Actually I might be wrong, they are both from Doctrine ... sigh
Still tho, it doesn't answer why in my original code, it returns multiple time
What about getSingleResult() rather than getResult() ? And you should maybe use the doctrine method findOneBy()
You can use the helper methods provided by the repositories, allowing you to fetch one or multiples entities from repositories with dynamic method names, in your case you want to fetch one post by id:
//fetch one
$replacementInstruction = $this->getDoctrine()->getRepository("AcmeBlogBundle:Post")->findOneById(6);
For information, fetching all entities is done with ->findByProperty

django-autocomplete-light add parameter to query url

I'm trying to pass some data along to the autocomplete_light.AutocompleteModelBase so I can exclude some models from the search. I'm trying to use the Dependencies info in the docs here
but I can seem to get it.
The id of the input is id_alternate_version-autocomplete, so I'm trying:
$("#id_alternate_version-autocomplete").yourlabsWidget().autocomplete.data = {'id': 'foo'};
But the url called looks like http://127.0.0.1:8000/autocomplete/FooAutocomplete/?q=bar
I want: http://127.0.0.1:8000/autocomplete/FooAutocomplete/?q=bar&id=foo
How can I do something like that?
DAL provides a way to do this with "forwarding" of another rendered form field's value.
See http://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#filtering-results-based-on-the-value-of-other-fields-in-the-form
This is how I did it:
$(document).ready(function() {
$('form#recipe').on('change propertychange keyup input paste', function() {
var ingredient_item_type = $("form#recipe input[type='radio']:checked").val();
var widget = $("form#recipe input#id_ingredients_text").parents('.autocomplete-light-widget');
if(ingredient_item_type) {
widget.yourlabsWidget().autocomplete.data['hello'] = 'world';
}
});
});
Javascript acrobatics aside, the key observation is thus:
anything you put in the .data object of the autocomplete widget will
automatically be made part of the GET request. HTH.

Doctrine paginator

I'm running into a problem with the Doctrine Paginator.
In my repository I have a function to retrieve a specific dataset.
I use the querybuilder for this:
{myEntityRepository}->createQueryBuilder($alias)
In order to select only specific fields I use the following:
if (count($selectFields) > 0) {
$qb->resetDQLPart('select');
foreach ($selectFields as $selectField) {
$qb->addSelect($alias . '.' . $selectField);
}
}
This works fine when I retrieve the whole set like this:
$query = $qb->getQuery();
$data = $query->getResult(AbstractQuery::HYDRATE_ARRAY);
But it fails when I use the paginator:
$paginator = new Paginator($qb, $fetchJoinCollection = false);
$total = $paginator->count(),
$data = $paginator->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY)
I get the error:
Not all identifier properties can be found in the ResultSetMapping:
relationID\vendor\doctrine\orm\lib\Doctrine\ORM\Query\Exec\SingleSelectExecutor.php(38)
Question: Why does the paginator fail when I select only specific fields?
Am I overlooking something? Or am I doing it wrong all together?
i am using this solution.
add use statements
use Zend\Paginator\Paginator;
use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator as DoctrineAdapter;
use Doctrine\ORM\Tools\Pagination\Paginator as ORMPaginator;
in your action
$viewModel = new ViewModel();
$entityManager = $this->getServiceLocator()
->get('Doctrine\ORM\EntityManager');
$queryBuilder = $entityManager
->createQueryBuilder();
$queryBuilder->add('select', new Expr\Select(array('t.id', 't.name')));
$queryBuilder->add('from', 'Application\Entity\Table t');
$adapter = new DoctrineAdapter(
new ORMPaginator(
$queryBuilder
)
);
$paginator = new Paginator($adapter);
$paginator->setDefaultItemCountPerPage(20);
$page = (int)$this->params()->fromQuery('page');
if($page) $paginator->setCurrentPageNumber($page);
$viewModel->results = $paginator;
return $viewModel;
Doctrine is trying to hydrate a relationship outlined by your YAML file, using a field that doesn't exist because you've excluded it from your SELECT statement. Take a look at your mapping file to figure out what you need to add back in.
I would think that it's only complaining with the Paginator because the field is not being accessed (and therefore not being lazy-loaded) when you don't use the Paginator.
As an aside (and with zero understanding of your stack, so YMMV) I would avoid making a habit of SELECTing reduced result sets, as you'll find yourself running into odd issues like this all the time. If you do need extra performance, you'd be better off putting a good old caching layer in place...

Adding a search box to filter a list of results in Symfony?

I need to put a search box within a list of objects as a result of a typical indexSuccess action in Symfony. The goal is simple: filter the list according to a criteria.
I've been reading the Zend Lucene approach in Jobeet tutorial, but it seems like using a sledge-hammer to crack a nut (at least for my requirements).
I'm more interested in the auto-generated admin filter forms but I don't know how to implement it in a frontend.
I could simply pass the search box content to the action and build a custom query, but is there any better way to do this?
EDIT
I forgot to mention that I would like to have a single generic input field instead of an input field for each model attribute.
Thanks!
I'm using this solution, instead of integrating Zend Lucene I manage to use the autogenerated Symonfy's filters. This is the way i'm doing it:
//module/actions.class.php
public function executeIndex(sfWebRequest $request)
{
//set the form filter
$this->searchForm = new EmployeeFormFilter();
//bind it empty to fetch all data
$this->searchForm->bind(array());
//fetch all
$this->employees = $this->searchForm->getQuery()->execute();
...
}
I made a search action which does the search
public function executeSearch(sfWebRequest $request)
{
//create filter
$this->searchForm = new EmployeeFormFilter();
//bind parameter
$fields = $request->getParameter($this->searchForm->getName());
//bind
$this->searchForm->bind($fields);
//set paginator
$this->employees = $this->searchForm->getQuery()->execute();
...
//template
$this->setTemplate("index");
}
It's important that the search form goes to mymodule/search action.
Actually, i'm also using the sfDoctrinePager for paginate setting directly the query that the form generate to get results properly paginated.
If you want to add more fields to the search form check this :)
I finally made a custom form using the default MyModuleForm generated by Symfony
public function executeIndex {
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
but displaying only a custom field:
<div id="search_box">
<input type="text" name="criteria" id="search_box_criteria" value="Search..." />
<?php echo link_to('Search', '#my_module_search?criteria=') ?>
</div>
Then I created a route named #my_module_search linked to the index action:
my_module_search:
url: my_module/search/:criteria
param: { module: my_module, action: index }
requirements: { criteria: .* } # Terms are optional, show all by default
With Javascript (jQuery in this case) I append the text entered to the criteria parameter in the href attribute of the link:
$('#search_box a').click(function(){
$(this).attr('href', $(this).attr('href') + $(this).prev().val());
});
And finally, back to the executeIndex action, I detect if text was entered and add custom filters to the DoctrineQuery object:
public function executeIndex {
...
// Deal with search criteria
if ( $text = $request->getParameter('criteria') ) {
$query = $this->pager->getQuery()
->where("MyTable.name LIKE ?", "%$text%")
->orWhere("MyTable.remarks LIKE ?", "%$text%")
...;
}
$this->pager->setQuery($query);
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
Actually, the code is more complex, because I wrote some partials and some methods in parent classes to reuse code. But this is the best I can came up with.