i am fetching a product collection and i want to use like condition on custom attribute but the problem is that while using like condition i want to remove all white space contain in my custom attribute value.
i have already tried
$psku = 'some_sku';
$_product = Mage::getModel('catalog/product')->getCollection();
$_product->addFieldToFilter(str_replace(' ', '', 'simple_skus_map'),
array(array('like' => '%,'.$psku.',%'),
array('like' => '%,'.$psku),
array('like' => $psku.',%'),
array('like' => $psku)
));
// simple_skus_map : (my custom attribute has data like one, two, three ,four). and i want the following code should fetch all the product which simple_skus_map contains any of the above mentioned word(i.e one/two/three/four)
NOTE: noticed? i have spaces in my custom attribute.
for custom attribute you can do as following, hence it will remove white space from your custom attribute value and match the given/post data
$_product = Mage::getModel('catalog/product')->getCollection();
$_product->addExpressionAttributeToSelect('trimmed_simple_skus_map',
'REPLACE({{simple_skus_map}},\' \',\'\')','simple_skus_map');
$_product->addFieldToFilter('trimmed_simple_skus_map', [
'finset' => [$psku]
]
);
The query as you supplied can perform slow, as it uses like with wildcards. You can use the find_in_set functionality.
Luckily magento supports this as well:
$_product = Mage::getModel('catalog/product')->getCollection();
// Trim spaces, 'save to column' trimmed_simple_skus_map
$_product->addExpressionAttributeToSelect('trimmed_simple_skus_map', 'REPLACE(sku,\' \',\' \')', 'simple_skus_map');
// Find in trimmed set
$_product->addFieldToFilter('trimmed_simple_skus_map', [
'finset' => [$psku]
]
);
I have another solution, with direct SQL queries.
here is the php code:
$resource = Mage::getSingleton('core/resource');
$readConnection = $resource->getConnection('core_read');
$writeConnection = $resource->getConnection('core_write');
$q_find_blank = "SELECT *FIELD_NAME* FROM simple_skus_map WHERE *FIELD_NAME* LIKE '% %'; ";
$results = $readConnection->fetchAll($q_find_blank); //get all field with a blank space
foreach ($results as $result){ //set all the fields in array and removes the blanks
$result = explode(' ',$result);
$no_blanks_fields[] = implode("",$result);
}
echo print_r($no_blanks_fields);
foreach ($no_blanks_fields as $no_blanks_field){ //replace them in the database field
echo $no_blanks_field . "<br>";
$q_update = "UPDATE simple_skus_map set *FIELD_NAME* = ".$no_blanks_field." WHERE *condition referencing the right field to his value*";
$writeConnection->query($q_update);
}
this is simply, not very high performance, but works.
Just remember when you write data make sure to set the correct value in the correct fields (you can maybe creating a temporary support table, with |field|id| ).
This will remove your blanks from the selected field, and replace them with a non blanks value(or whatever you want to implode them with, just check the implode function).
"test field blanks" => "testfieldsblanks"
Related
Not sure how to title this properly but here's the issue I am running into currently. I built a cart and checkout system and it loads all the data into a database when it finalized the order. To save some space, I stored just the item IDs originally but then I ran into the issue of if I deleted the item from the database (because it was discontinued or whatever) then it wouldn't return the info I needed. And if they ordered more then 1 item the database record would be wrong. So I stored the data like so:
Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2
OR
1:3:20.00:Flower Hat, 2:1:17.75:diamonds
The issue I have right now that I need help with is this. I need to seperate the four values into variables like $price, $item, $id, $ammount so I can display them on the order history page and I need to loop through all items on the array so I can print a row for each item with all four fields respective to that item.
I use strpos already to get the shipping info from the same database field which is formatted as METHOD:Price but since I have 3 :'s on my string I'm not sure how to go through each one. Thanks.
Here's a function
function parseItems($dbjunk){
$cart = array();
$items = explode(",",$dbjunk);
foreach($items as $i){
$chunks = explode(":", $i);
$cart[] = array(
"ItemID" => $chunks[0] ,
"Quantity" => $chunks[1] ,
"Price" => $chunks[2] ,
"name" => $chunks[3]
);
}
return $cart;
}
Example usage:
$dbjunk = "Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2";
$parsed = parseItems($dbjunk);
print_r($parsed);
See: https://3v4l.org/rBkXF
If you need variables instead of an array you can use list(), like this..
$dbjunk = "Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2";
$parsed = parseItems($dbjunk);
foreach($parsed as $p){
list($itemID, $Quantity, $Price, $name) = array_values($p);
var_dump($itemID, $Quantity, $Price, $name);
}
see: https://3v4l.org/l4vsn
You should not physically delete items from your database. Instead, put a new column named 'is_active' or something like that to indicate whether the product is active/non-deleted.
Answering your question, here is my suggestion:
$orderString = '1:3:20.00:Flower Hat, 2:1:17.75:diamonds';
$items = array();
foreach(explode(', ', $orderString) as $itemString) {
$itemData = explode(':', $itemString);
$items[] = array(
'id' => $itemData[0],
'amount' => $itemData[1],
'value' => $itemData[2],
'description' => $itemData[3]
);
}
with this code, you will obtain an array with the data of all the items in the string, no matter how much items are in the string
try something like
$data = 1:3:20.00:Flower Hat, 2:1:17.75:diamonds
list($price, $item, $uid, $id, $ammount) = explode(":", $data);
echo $user;
echo $item;
Read about First Normal Form. Basically, you want to store one value in one field. So, instead of this:
shipping = "method:price"
You want something like this:
shipping_method = "method"
shipping_price = "price"
Don't concern yourself with space -- it's essentially free nowadays.
Regarding your deleted items dilemma, your initial implementation was the way to go:
I stored just the item IDs originally
In addition to reverting to this technique, I would recommend two things:
Add a boolean field to your item table to represent if the item is currently available or not. This gives you the additional feature of being able to toggle items on/off without having to delete/insert records and change ids.
Before deleting an item, check to see if it's ever been ordered. If not, it's ok to delete. If so, instead just deactivate it.
I want to apply search filters in my project. I have options tables where options are being saved with the option values with parent id of option id. For example brand is saving as option with parent id set to 0 and all brands have brand id as their parent id set and while saving product I am saving product options in product_options table. Now i want to apply filters in product listing page. I am using following code for filtration:
$conditions = array();
$product_options = $this->ProductOption->find('list',array('fields'=>array('product_id'),'conditions'=>array('ProductOption.option_value_id'=>$data['data']['options'])));
$conditions = array_merge($conditions,array('Product.id'=>array_unique($product_options)));
$prod_info = $this->paginate('Product',$conditions);
$this->set(compact('prod_info'));
When I search any product with their brand name it works fine but if I try to search with the price (also an option) then it gives other brand products also which have price equal to filter price option. Please check following link to understand problem correctly.
http://primemart.in/Food-Processors-Ii4zRGAKYAo=
Please anyone help me to come out my problem.
Thanks.
Please have a look on my code which I used to pass conditions in and to get results
$product_options = $this->ProductOption->find('list',array(
'fields'=>array('product_id'),
'conditions'=>array('ProductOption.option_value_id'=>$data['data']['options'])
));
//$this->Option->unBindModel(array('belongsTo'=>'Product'));
$product_options = $this->Option->find('all', array(
'conditions'=>array('Option.id'=>$data['data']['options'])
));
//pr($product_options);
$opt_arr = array();
foreach ($product_options as $op) {
$opt_arr[$op['Option']['parent_id']][] = $op['Option']['id'];
}
$conditions_arr = array();
foreach($opt_arr as $opt) {
$key_arr = array();
foreach($opt as $op) {
$key_arr['OR']['ProductOption.option_value_id'][] = $op;
}
$conditions_arr['AND'][] = $key_arr;
}
$pr_options = $this->ProductOption->find('list', array(
'conditions'=>$conditions_arr,
'fields'=>array('product_id')
));
$conditions = array_merge($conditions, array('Product.id'=>array_unique($pr_options)));
I would try code bellow. I assume that $conditions constist of the other conditions you mention in your question.
$conditions = ... // other conditions you mentioned
$conditions = array('AND'=>array($conditions, array('Product.id'=>array_unique($product_options))));
$prod_info = $this->paginate('Product',$conditions);
I use the following code to strip the product number from a page url so that i can query a database to check for a custom canonical link.
$qs = explode('&',$_SERVER['QUERY_STRING']);
$prodid = explode('=',$qs[0]);
$prod_ID = $prodid[count($prodid)-1];
As an example, $qs contains
Array ( [0] => products_id=1121 [1] => cPath=180_182 [2] => )
I then decided i also needed to be able to specify custom canonicals for the categories as well so i added the following code:
$catid = explode('=',$qs[1]);
$lastnmbr = explode('_',$catid[1]);
$cat_ID = $lastnmbr[count($lastnmbr)-1];
This gives me $prod_ID of 1121 and $cat_ID of 182.
However, here is the problem. If i drop back to the product list rather than a specific product page the array held in $qs becomes Array ( [0] => cPath=180_182 [1] => ) which means that
$catid = explode('=',$qs[1]);
is no longer the correct array position to collect the category id and in fact it is collected by
$prodid = explode('=',$qs[0]);
which makes all the following code think it's a product.
I think i need to somehow use the information held before the = symbol to ensure that if it says cPath it assigns it to $catid and if it says products_id it assigns it to $prodid.
Is there a "correct" way to do this? I did try making a new var of
$catchk = explode($qs[0], '=');
thinking this would return the data BEFORE the = symbol but it didn't so i obviously have the wrong end of the stick here.
To make the solution clear, i used the suggestion from Tyr (Thank you) and finished up with
$catid = $_GET['cPath'];
$lastnmbr = explode('_',$catid);
$cat_ID = $lastnmbr[count($lastnmbr)-1];
$prod_ID = $_GET['products_id'];
It was necessary to be able to strip the set of numbers following the last _ (underscore) as subcategories are shown as 180_182 etc
What if you trying $_GET['product_id'] and $_GET['cPath'] instead of $_SERVER['QUERY_STRING'] usage?
You are avoiding the problems of having the correct array path.
I have a photo website on which I am trying to perform a query against a MySQL database. The query is against a concatenated field of 'title' and 'keyword' called 'title_keyword'.
I want to take the search results and sort them by a newly formed variable called 'sort_priority' which is checking to see if the search word is in the 'title' field. If it is in the 'title' field then I want to assign a value of 1 and if not in the title field then a value of 2. The resulting array will be sorted by 'sort_priority' and output to the screen.
Here is the logic I am using with PHP and MySQL:
1) Query the MySQL database and assign variables. (This works just fine)
2) Take the results, assign each field to a variable, create a new variable that performs a calculation on one of the variables returned
$data_array=array();
// get each row
while($row = mysql_fetch_array($result))
{
//get data
$image_id = "{$row['image_id']}";
$title = "{$row['title']}";
$imageurl = "{$row['imageurl']}";
// Create sort_priority to identify if search word is in title field.
//If it is then set to 1 to force this higher in the result list after sorting
$sort_priority = 2;
if(stristr($title,$search))
{ $sort_priority = 1;}
Everything above this point works. Now for the part I'm stumped on. How to create and add data to the array and then sort on my new $sort_priority variable.
Here is what I've written but it just doesn't work**
// Create array and sort by title then keyword (tk_sort)
$data_array = array(
'image_id' => $image_id,
'title' => $title,
'imageurl' => $imageurl,
'sort_priority' => $sort_priority);
// Obtain a list of columns
foreach ($data_array as $key => $row) {
$image_id[$key] = $row['image_id'];
$title[$key] = $row['atitle'];
$imageurl[$key] = $row['imageurl'];
$sort_priority[$key] = $row['sort_priority'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($sort_priority, SORT_ASC);
// end of array creation and sort
3) Output the newly sorted array to a table
Not sure how to get the data out of it. Do I have to use a loop or something?
You could just let MySQL do the majority of the work. This should work (haven't tried it myself):
SELECT CONCAT_WS('-', `title`, `keyword`) AS search_term,
IF( INSTR(`search_term`, 'your_search_value_here') > 0, 1, 2 ) AS priority_key,
`image_id`, `imageurl`
FROM table_name_here
ORDER BY `priority_key`;
HTH.
What is the "proper" way to get the value stored in a particular field within a custom Drupal node? I've created a custom module, with a custom node, with a custom URL field. The following works:
$result = db_query("SELECT nid FROM {node} WHERE title = :title AND type = :type", array(
':title' => $title,
':type' => 'custom',
))->fetchField();
$node = node_load($result);
$url = $node->url['und']['0']['value'];
...but is there a better way, maybe using the new Field API functions?
node_load() then accessing the field as a property is the proper way, although I'd do it slightly differently to avoid hard-coding the locale:
$lang = LANGUAGE_NONE;
$node = node_load($nid);
$url = $node->url[$lang][0]['value'];
The method you're using to get the nid is a particularly kludgy way to derive it; I'd focus on refactoring that and use EntityFieldQuery and entity_load() instead:
$query = new EntityFieldQuery;
$result = $query
->entityCondition('entity_type', 'node')
->propertyCondition('type', $node_type)
->propertyCondition('title', $title)
->execute();
// $result['node'] contains a list of nids where the title matches
if (!empty($result['node']) {
// You could use node_load_multiple() instead of entity_load() for nodes
$nodes = entity_load('node', $result['node']);
}
You'd want to do this especially since title is not a unique property and if the field appears on entities other than nodes. In that case you'd remove the entityCondition().
Not sure why EntityFieldQuery is being discussed, but ok. :) You're actually going to want to use the field_get_items() function.
if ($nodes = node_load_multiple(array(), array('type' => 'custom', 'title' => $title)) {
$node = reset($nodes);
if ($items = field_get_items('node', $node, 'url')) {
$url = $items[0]['value'];
// Do whatever
}
}
propertyCondition('field_order_no', 'value', 'search key', '=')
field_order_no is the slug of custom field & Search Key is the value to be matched with