Apachesolr query - filter by text in fields - drupal

I'm constructing an apachesolr query in my Drupal module programmatically and have had success with some aspects, but am still struggling with others.
So far, I have been able to construct a query that can search for specific text and limit the results based on terms to be filtered by with the following code:
$subquery_region->addFilter('tid', $term->tid);
$query->addFilterSubQuery($subquery_region, 'OR', 'AND');
What I'd like to achieve next is to be able to narrow the search further by adding a filter for finding certain text within a specific field in the node. Has anyone been able to do this.
I've been researching online and have tried lots of different ways such as adding the filter directly to the main search query
$query->addParam('fl', 'ss_my_field');
$query->addFilter("ss_my_field", "field_substring_to_search_for");
As well as breaking that out into a subquery to add to the main search query
$subquery_test = apachesolr_drupal_query("Test");
$subquery_test->addParam('fl', 'ss_my_field');
$subquery_test->addFilter("ss_my_field", "field_substring_to_search_for");
$query->addFilterSubQuery($subquery_test, 'OR', 'AND');
But none of these are working. They are returning an empty set, even though I know the substring exists in the field I'm adding as a filter and it has been indexed. I have verified through the apachesorl views module that the search index has been populated with that field and can see the substring exists.
Is there anything wrong with my syntax or the way I'm building the query?
If you know how to add filters for searching for text within certain fields, please share! It may not even be done with the addFilter function, but that's all I have been trying so far.
Thanks!

First you have to create an index for that specific field.
function hook_apachesolr_update_index(&$document, $node) {
$document->ss_your_field_name = $node->your_field_name;
}
where ss_* is the pattern.
ss_* -> String
is_* -> Integer
im_* -> Integer, Multivalued
After that you have to
1. delete the index - admin/settings/apachesolr/index
2. re-index the content
3. run the cron
4. check the filter that you created - admin/reports/apachesolr/index
Then, you can add filters
$query->addFilter("ss_your_field_name", "value");
Hope this helps you.

function hook_apachesolr_modify_query(&$query, &$params, $caller){
$subquery = apachesolr_drupal_query();
$subquery->add_filter("ss_my_field", "field_substring_to_search_for");
$query->add_subquery($subquery, "AND");
}

Related

How to check if an order number exists in woocommerce?

In my WooCommerce store, I have an input field where I want the user to enter the order number. When validating this field, I need to check if that order number actually exists in WooCommerce.
From this question, it seems like the WooCommerce order_number might not always be the same as the order_id (which is always the same as the post_id).
So I can't use wc_get_order($the_order) function since the documentation states that it wants the post_id in the $the_order parameter.
I can't find a specific function to get the order by the order number (neither in the documentation nor the code in github).
I'm fairly new to WooCommerce, so maybe I am missing something. Is there a way to do this at all? Or is the wc_get_order mis-documented?
I've done a lot of googling and searching here on stack overflow, but I really can't find the answer to this! Any help is appreciated.
PS: I suppose I could get all orders and loop through them one by one checking if the number matches, but I was hoping to find a simpler solution to this :D
You may try this if statement to see if given ID (number) is an Order Number or not:
function is_it_a_shop_order($givenNumber)
{
if(get_post_type($givenNumber) == "shop_order")
{
echo "yes this is a valid order number";
}
else
{
echo "no go away";
}
}
Wordpress stores all posts (pages, orders, products etc.) in wp_posts table and orders are stored with post type named "shop_order".
I tested the code. I hope this will help you. Have a good day.
The reason you're struggling to find anything about this in the documentation is because WooCommerce has no native concept of an order number. The ID is the order number.
What store owners tend to find however is that order IDs don't increase sequentially. There can be a large jump in ID between one order and the next because of the way WordPress handles posts. Often users will install a plugin to address that. It's those plugins that introduce the differentiation between order IDs and what they refer to as the order number.
Here's an example of one such plugin: https://en-gb.wordpress.org/plugins/woocommerce-sequential-order-numbers/
Included in the documentation is an example of how to find an order by its number. If you have one of these plugins installed, you'll simply need to lookup how the plugin in question resolves numbers to IDs.
Send the order number through the wc_get_order call. If the returned array is empty, the order number does not exist.
$bOrderExists = DoesOrderExist($OrderNumber);
function DoesOrderExist($OrderNumber)
{
$orderq = wc_get_order($OrderNumber);
if(empty($orderq))
return 0;
return 1;
}

Calculated_SQL Table - Search

i have done a calculated sql with a custom query.
Implemented a table from that data model.
Until here we are ok.
My problem is the next step:
In my custom query i have a field concatAll(that is all fields concatenated).
In my page i want to put a search box to do a "contains" search in my field concatAll and present those results in my table.
Anyone knows how to do this?
Tried multiple approaches, but could not have the result.
Thanks
As #Pavel Shkleinik send to me this is possible using :params in the query of calculated_sql.
Example:
or (c.phone like concat(CONCAT("%", ifnull(:concatAll,''), "%")))
and you put concatAll as a string parameter on datasource page.
Regards

Drupal - Views. Setting a filter programmatically

I hope this is not a stupid question I have been searching for most of the day!
I have a Content Type (Documents) which simply contains a title, file and a category. The category value is required and is 'powered' by Taxonomy.
I now wish to create a view which will display these documents grouped and titled by the taxonomy term.
Using my limited Drupal knowledge I intent to iterate through the relevant terms IDs (using taxonomy_get_tree($vid)) and then render each view accordingly.
To do this I have been hoping to use this snippet.
view = views_get_view('documents');
$view->set_display($display_id);
$filter = $view->get_item($display_id, 'filter', 'field_dl_category');
$filter['value']['value'] = $filter_value;
$view->set_item($display_id, 'filter', 'field_dl_category', $filter);
$viewsoutput = $view->render();
But this is not working; when I query the value of the $filter ($view->get_item($display_id, 'filter', 'field_dl_category')) I get null returned.
Might this be that my filter name is not the same as the CCK field name?
I am using Drupal 7.
Any help much appreciated, I am running out of ideas (and time).
I finally managed to get this working but I took a slightly different approach.
I changed my view and added the relevant contextual filter and then used this function views_embed_view to get at my required results.
If this helps! this is my solution:
$display_id = 'default';
$vid = 7;
$terms = taxonomy_get_tree($vid);
foreach($terms As $term){
$content = views_embed_view('documents', $display_id, $term->tid);
//now we see if any content has been provided
if(trim($content) != ''){
print "<h3>" . $term->name . "</h3>";
print $content;
}
}
In my case the trim($content) returns '' with no data as the view template has been edited, this might not be the case for all.
I am a very new Drupal developer so I'm sure there are much better ways of doing this, if so please do post.
I am going to go ahead and assume that you want to show, using Views, a list of document nodes grouped by the category that they have been tagged with.
There are two (of maybe more) ways by which you can do this in Views 3:
(a) Choose a display style that allows you to select a Grouping field. (You could try the table style that ships with Views by default). Suppose you have properly related the node table to the taxonomy_term_data table through a Views relationship, you could choose taxonomy_term_data.name as the grouping field.
Note that this grouping is done before the view is just rendered. So, your query would just have to select a flat list of (content, tag) pairs.
(b) You could also make use of the Attachment display type to achieve something similar. Show the used categories first in a list view clicking on which will show a page (attachment) with all documents tagged in that chosen category.
To understand how to do (a) or (b), turn on the advanced_help module (which is not a Views requisite but is recommended) first.
For (a), read the section on Grouping in styles i.e. views/help/style-grouping.html and
For (b), read the section on Attachment display i.e. views/help/display-attachment.html
A couple of things about your approach:
(a) It will show all terms from that vocabulary irrespective of whether or not they were used to tag at least one document.
(b) views_embed_view() will return NULL even if the currently viewing user does not have access to the view. So, ensure that you catch that case.
Here's an alternative:
$view = views_get_view('view_machine_name');
$view->init_display('default');
$view->display_handler->display->display_options['filters']['your_filter_name']['default_value'] = 'your_value';
$view->is_cacheable = FALSE;
$view->execute();
print $view->render();
I know you can probably set this using some convoluted method and obviously that would be better. But if you just want a quick and dirty straight access without messing around this will get you there.

After join, cannot filter by attribute qty - getting products from inventory that are in stock

You have been so helpful in the past that I keep coming back searching for help and learning.
This time I am trying to get all products that have a quantity greater than 1 and that are in stock (is_in_stock = 1)
$products = Mage::getModel('catalog/product')->getCollection();
//$products->addAttributeToSelect('*');
//SELECT `e`.*, `stock`.`qty` FROM `catalog_product_entity` AS `e` LEFT JOIN `cataloginventory_stock_item` AS `stock` ON stock.product_id = e.entity_id
$products->getSelect()->joinLeft(
array('stock'=>'cataloginventory_stock_item'),
'stock.product_id = e.entity_id',
array('stock.qty', 'stock.is_in_stock')
);
This returns qty and is_in_stock columns attached to the products table. You can test it as follows:
$products->getFirstItem()->getQty();
$products->getFirstItem()->getIsInStock();
The issue begins when I try to filter by qty and is_in_stock.
$products->addFieldToFilter(array(
array('Qty','gt'=>'0'),
array('Is_in_stock','eq'=>'1'),
));
This returns - Invalid attribute name never performing filtering. I am guessing it is trying search for e.qty but cannot find it.
So, I tried to filter differently:
$products->getSelect()->where("`qty` > 0");
$products->getSelect()->where("`is_in_stock` = 1");
This is not filtering as well even though, if you look at its sql query, (var_dump((string) $products->getSelect())), and run that query in phpMyAdmin, it works.
Alan Storm in his tutorial mentions that 'The database query will not be made until you attempt to access an item in the Collection'. So, I make the $products->getFirstItem() call but it still not executing the query or filtering in another words.
What am I doing wrong? Any ideas how to filter by attributes that are joined to the table?
Thank you again,
Margots
I would suggest that you try using $products->addAttributeToFilter... instead of $products->addFieldToFilter... - the addField method only works when the field is on the main table that you are querying (in this case catalog_product_entity). Because the inventory fields are in a joined table, you need to use addAttribute.
Hope this helps,
JD
After looking under the hood I learned that _selectAttributes instance field was not assigned in Mage_Eav_Model_Entity_Collection_Abstract class and that is why get exception. A solution usually would be what Jonathan Day suggested above - add addAttributeToFilter() method, however. It will return error since it cannot find such attribute for catalog/product. (qty and in_invetory are in cataloginventory_stock_item). I found two solutions to my problem both required going different direction:
One involved pursuing a way to query the Select statement that I had set for product collection(see above) but somehow it was not resetting the collection with new product. WhenI copied that Sql statment in phpMyAdmin, it worked, so how to query that statement from product collection:
$stmt = $products->getConnection('core_write')->query($products->getSelect()->__toString());
while($rows = $stmt->fetch(PDO::FETCH_ASSOC)){
echo "<br>Product Id ".$rows['entity_id'];
}
Instead of using catalog/product entity table I used the flat table - cataloginventory_stock_item to accomplish the same thing
$stockItem = new Mage_CatalogInventory_Model_Stock_Item();
$stockItems->addQtyFilter('>',0);
$stockItems->addFieldToFilter('is_in_stock',array('eq'=>'1'));
Now there is a collection of all products with qty > 0 and that are in stock.

How do you get a Min() or Max() in drupal using views?

I'm using Drupal's Views 2, and need to retrieve min values from fields in a custom table. The query for this is easy if I were writing it by hand--something like, "SELECT foo, min(bar) FROM table GROUP BY foo." But how would I do this using Views? I've already defined the table in a views.info file, so there's no trouble getting views to see the table. It's the Min() part of the query I just don't understand. My next stop will be the Views API documentation, but if someone can just provide the outline for how to do this quickly, I would greatly appreciate it.
New answer to an old question, but something like this will work. You need to create a custom field handler and then wrap the field as follows:
class views_handler_custom_field extends views_handler_field {
function query() {
$this->ensure_my_table();
$this->field_alias = $this->query->add_field("MAX({$this->table_alias}", "{$this->real_field})",$this->table_alias . "_" . $this->real_field);
}
}
Use aggregation from advanced configuration of views. After this is set
yes you can select max, min or any other selector to fields.
Test your results but it should work well
Alternatively in some cases you can sort your data ascending or
descending and then just pick one to be shown on the view. Can be
problematic when displaying multiple fields or so.
After testing first one seems to be faster at least on small scale.
One could consider the modules groupby and views_calc, but I assume they are not acceptable for you.
Additionally, you can accomplish this with a custom module.

Resources