Multiple orderby within Criteria - symfony

I currently use the Criteria to filter a collection of objects. But when I want to achieve with 2 orderBy fields, only the first is considered. I do not understand.
$events = new Collections\ArrayCollection($results);
$dateFrom = new \DateTime($date);
$dateTo = new \DateTime(date('Y-m-d H:i:s', strtotime($date . ' + 1 day')));
$criteria = Criteria::create()
->where(Criteria::expr()->eq('activity', $activity));
$criteria->orderBy(array(
"time" => "ASC",
"title" => "ASC"
));
How can I make it work with two orderby fields and not only the first ?
Thank you in advance for any answers !

Your code is correct, assuming that $criteria is then applied correctly to the ArrayCollection.
Judging by the names of your fields you're trying to order by, it's possible that title doesn't affect the order because time doesn't repeat among the elements in the collection.
If this isn't the case, please provide more information on the results you're getting and I will update my answer.
Update (in response to additional data provided that has since been deleted):
You are sorting the collection correctly. The problem is that you're then feeding the ArrayCollection into the Paginator, which apparently cannot sort by more than one field.
There's an open issue in Knp's tracker about this: https://github.com/KnpLabs/KnpPaginatorBundle/issues/109.

Related

Why findAll() working and find($id) not?

I am facing one problem when getting data in tabs. When I am using
$settingsList = $this->getDoctrine()->getRepository('AppBundle:J1Setting')->
findAll();
all data is showing in all tabs.
Now, when I want to filter by 'id'
$settingsList = $this->getDoctrine()->getRepository('AppBundle:J1Setting')->
find(1);
It shows nothing.
When I am looking into profiler the query returns one row.
As suggested by #zerkms above in comments find only returns single entity. So, I have used findBy like this:
$settingsList = $this->getDoctrine()->getRepository('AppBundle:J1Setting')->
findBy(array('groupId' => '1'));

How to set parameters in nested query in DQL

Hi,
I'd like to get number of created articles by a user, the query used to work until I added some parameters filtering the query by "fromDate" and "toDate" dates, here's my query :
// query String
$dql = 'SELECT u.idUser,
u.lastName,
u.email,
u.mobile,
(SELECT AVG(n.note)
FROM MyBundle:Note n
WHERE n.noteFor = u.idUser) AS note,
(SELECT COUNT(a)
FROM MyBundle:Article a
WHERE (a.createdBy = u.idUser) AND (a.createdAt BETWEEN :fromDate AND :toDate)) AS articles
FROM MyBundle:User u';
// create the actual query
$users= $em->createQuery($dql);
// set filter date parameter
$users->setParameter('fromDate', $fromDate.'00:00:00');
$users->setParameter('toDate', $toDate.'23:59:59');
I keep getting this error : Invalid parameter number: number of bound variables does not match number of tokens.
I tried searching in the doctrine documentation for how to set parameters in nested queries without finding anything. first I need to know if it's possible to do that then find where the error come from, Please Help !
Use setParameters() instead of setParameter()
$users->setParameters(array('fromDate'=> $fromDate.'00:00:00','toDate'=> $toDate.'23:59:59'))
So after performing some tests, I found out that the query worked well the way it was and the problem wasn't there.
I'm using KnpPaginatorBundle to paginate my queries, it seems that the problem was that it couldn't paginate complex queries like passing multiple parameters in the nested query. so I found a solution. So this is the old code :
// Pagination
$paginator = $this->get('knp_paginator');
$users = $paginator->paginate($users, 1, 10);
And this is the new code :
// Pagination
$paginator = $this->get('knp_paginator');
$users = $paginator->paginate($users, 1, 10, array('wrap-queries' => true) );
Thanks to Nisam and Matteo for their time, hope this helps someone

Add Table Join, Where, and Order By to Views Query in views_query_alter()

I am trying to modify the query for Views in Drupal (Views version 3, Drupal version 7).
What I want to do is change the query prior to running such that it LEFT JOINs a table in which I have weights assigned to the nodes.
If I was to write the query I want in SQL, it would look like this:
SELECT a.nid, a.title, a.description
FROM node a
LEFT OUTER JOIN node_weights b
ON a.nid = b.nid
WHERE b.uid = $uid
ORDER BY b.weight DESC
This query works like a champ when I run it in the query analyzer. So, now I need to make it work in my module.
I've seen multiple approaches detailed on various blogs for different ways to modify View queries, but they seem to be addressing different versions of Views. So it is very confusing to try to determine whether anything I'm looking at could even possibly work for my application.
It seems that I need to use a MODULE_NAME_views_tables() function to tell Views what the relationship is between the table I want to join and the node table.
I've added the following functions to MODULE_NAME.views.inc:
function MODULE_NAME_views_tables() {
$tables['node_weights'] = array(
"name" => "node_weights",
"join" => array(
"left" => array(
"table" => "node",
"field" => "nid"
),
"right" => array(
"field" => "nid"
),
),
);
return $table;
}
This does seem to be working because when I use Krumo to look at the query array, I see my "node_weights" table in the "table_queue" element.
In the views_query_alter() function, I'd like it to work something like this:
function MODULE_NAME_views_query_alter(&$view, &$query) {
$uid = $_COOKIE['uid'];
$view->query->add_relationship('node_weights', new views_join('node_weights', 'nid', 'node', 'nid','LEFT'));
$view->query->add_where('node_weights', "node_weights.uid", $uid);
krumo($query);
}
This function barfs pretty badly. Although my join table is appearing in the $view object, the add_relationship method is throwing an error for a 3rd argument, but I don't see any examples online that have 3 arguments so I don't know what it's missing.
Also, I'm pretty sure my add_where method isn't correct, but I don't know what the inputs should actually be. This is just a blind guess.
The bottom line is that I want to join the node table to my node_weights table, and then make sure my weights are used in the query to sort the results in a descending fashion where the user id = the user id in my table, and the tables are joined on the nid field.
Thanks in advance.
WHEREs are pretty easy to add once you've got the JOIN in. You can both in a query alter (Drupal 7).
function MODULE_NAME_views_query_alter(&$view, &$query){
// Only alter the view you mean to.
if($view->name == 'VIEW NAME' && $view->current_display == 'DISPLAY'){
// Create the join.
$join = new views_join();
$join->table = 'table_name';
$join->field = 'entity_id';
$join->left_table = 'node';
$join->left_field = 'nid';
$join->type = 'left';
// Add the join the the view query.
$view->query->add_relationship('table_name', $join, 'node');
// Add the where.
$view->query->where[1]['conditions'][] = array(
'field' => 'table_name.collumn_name',
'value' => 'value',
'operator' => '='
);
}}
I found the OP's comments helpful in creating a join in the hook_views_query_alter function, so I wanted to put the parts I found useful in a more digestible answer.
I was using Views 2x on Drupal 6x, but I assume it would be very similar to use on D7 Views 2.
The OP mentions describing the relationship of the join in hook_views_table. This wasn't necessary for me, as I was not linking to a custom table, but one that existed in core.
The join creation in the HOOK_views_query_alter() function was very helpful though:
$join = new views_join;
$join->construct('table_name',
'node', // left table
'nid', // left field
'nid', // field
)
See views_join::construct documentation for more information. In particular, I didn't need to use the 'extra' parameter that the OP used. Perhaps this is necessary with a custom table.
Finally, add the join to the query, and whatever other elements are needed from it:
// Add join to query; 'node' is the left table name
$view->query->add_relationship('table_name',$join,'node');
// Add fields from table (or where clause, or whatever)
$view->query->add_field('table_name','field_name');
...
You already have the $query in parameters, so you can just do:
myhook_views_query_alter(&$view, &$query) {
if ($view->name = ....) {
$join = new views_join();
$join->construct(
...
);
$query
->add_relationship(...)
->add_where(...)
->add_orderby(...)
...
;
}
No need to use $view->query->...

Magento: how to merge two product collections into one?

if i have two product collections is there a way to merge them into one?
for example (my final intent isn't to actually just get a collection of 2 cats, this is just to illustrate the issue):
$collection1 = Mage::getModel('catalog/category')->load(148)->getProductCollection();
$collection2 = Mage::getModel('catalog/category')->load(149)->getProductCollection();
$merged_collection = merge_collections($collection1,$collection2);
any help would be appreciated!
Assuming the items you wish to group together are of the same type and exist in the database then you can do this:
$collection1 = Mage::getModel('catalog/category')->load(148)->getProductCollection();
$collection2 = Mage::getModel('catalog/category')->load(149)->getProductCollection();
$merged_ids = array_merge($collection1->getAllIds(), $collection2->getAllIds());
// can sometimes use "getLoadedIds()" as well
$merged_collection = Mage::getResourceModel('catalog/product_collection')
->addFieldToFilter('entity_id', array('in' => $merged_ids))
->addAttributeToSelect('*');
Here I know to filter by entity_id because that is products' key field, like it is for most entity types, some flat tables have a different primary key. Often you can generalise that with one of the collection's getIdFieldName() method. Products are a bad example in this case because it's ID field name isn't filled out correctly.
Almost every (or every?) collection in Magento inherits from a Varien Data Collection. A collection is a special object that holds objects of another type. There's no method for merging collections, but you can add additional items of the appropriate type to the collection.
Code like this should get you where you want to go, although there's probably more efficient ways to loop and do the actual merging.
$collection1 = Mage::getModel('catalog/category')->load(148)->getProductCollection();
$collection2 = Mage::getModel('catalog/category')->load(149)->getProductCollection();
//load an empty collection (filter-less collections will auto-lazy-load everything)
$merged = Mage::getModel('catalog/product')->getCollection()->addFieldToFilter('entity_id',-1);
//add items from the first collection
foreach($collection1 as $item)
{
$merged->addItem($item);
}
//add items from the second collection
foreach($collection2 as $item)
{
//magento won't let you add two of the same thing to a collection
//so make sure the item doesn't already exist
if(!$merged->getItemById($item->getId()))
{
$merged->addItem($item);
}
}
//lets make sure we got something
foreach($merged as $product)
{
var_dump($product->getName());
}
I don't think there is such a method, but you can probably do something like that :
foreach ($collection1 as $item){
$collection2->addElem($item);
}
you can filter your collection directly without using 2.
$products = Mage::getModel('catalog/product');
$_collection = $products->getCollection();
->addCategoryFilter(2)
->load();
or try using 'addItem' to add your results to a collection. See also in Magento wiki
for the collection of products of several categories, you can use the following code
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToSelect('sku');
$collection->getSelect()
->join(
'catalog_category_product',
'product_id=entity_id',
array('category_id')
)
->where('catalog_category_product.category_id IN (?)', $categories);

How to use multiple filters to widen the search in Apachesolr queries

Making a search with Apachesolr, i want to add a couple of filters in hook_apachesolr_prepare_query(&$query). This works fine, except I want the filters to widen the search ('OR'), rather than narrow it ('AND').
For example, if I have 4 nodes of type:A and 3 of type:B that match a search, to filter by type:A and type:B should return 7 nodes (of type:A AND nodes of type:B), rather than 0 those of type:A which are also of type:B.
I saw a suggestion to do this using the model of nodeaccess
foreach ($filters as $filter) {
$subquery = apachesolr_drupal_query();
if (!empty($subquery)) {
$subquery->add_filter('type', $filter);
$query->add_subquery($subquery);
}
}
but this doesn't seem to work. (It doesn't return any results).
I then tried (as I have a limited number of node types) excluding the types that I don't want:
$excludes = array('A', 'B', 'C');
$excludes = array_diff($excludes, $filters);
$exclude = implode('&', $excludes);
$query->add_filter('type', $exclude, TRUE);
This method of stitching them together doesn't work (the '&' gets escaped) but neither does adding them as subqueries, similar to the manner above.
Any suggestions on how to do this?
With Drupal7 and the last apacheSolr API, you can do OR filters by doing this :
function my_module_apachesolr_query_alter($query) {
// first, create a subQuery filter to store others
// and specify there is a "OR" condition
$filter = new SolrFilterSubQuery('OR');
// next, add all filters on bundle you want, each as
// a new subQuery filter, always with "OR" condition
// and add it to the primary filter
$a = new SolrFilterSubQuery('OR');
$a->addFilter('bundle', 'A');
$filter->addFilterSubQuery( $a );
$b = new SolrFilterSubQuery('OR');
$b->addFilter('bundle', 'B');
$filter->addFilterSubQuery( $b );
$c = new SolrFilterSubQuery('OR');
$c->addFilter('bundle', 'C');
$filter->addFilterSubQuery( $c );
// finally, add the primary subQuery filter as
// subquery of the current query
$query->addFilterSubQuery( $filter );
}
And your query search about type A OR type B OR type C (all results in each types). You can combine OR / AND by changing the parameter of the SolrFilterSubQuery instanciation.
Special thanks to this page and it's author : http://fr.ench.info/blog/2012/04/03/Add-Filters-ApacheSOLR.html
I havenť played with SOLR much but I am quiete familiar with Drupal and Zend Lucene (or Drupal Lucene API).
I would suggest that you try to filter your results based on content type (because each node has its content type stored in the object).
The second idea is to change basic operator. I am not sure how it is done in SOLR but i Zend Lucene
Zend_Search_Lucene_Search_QueryParser::setDefaultOperator($operator) and Zend_Search_Lucene_Search_QueryParser::getDefaultOperator() methods, respectively.
Docs can be found in Zend Lucene Docs. Or for SOLR Solr Docs.
I hope a got your problem right.
Hope it helps :-)

Resources