I am working on some scripts to automate some things inside our webshop.
I have looked through many forums and questions.
Now I almost have finished my script but there is a small thing that doesn't work but I can not think of what I am doing wrong.
What the goal of this script is, is to get products that has the same attribute value as the values in an array (pulled from DB).
So here is my code:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once('../app/Mage.php');
require_once('db.php');
Mage::app();
$db = db_connection();
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ean');
$getean = $db->prepare('SELECT ean_l FROM mytable');
$getean->execute();
$allean = $getean->fetchAll();
foreach($allean as $ean) {
$collection->addFieldToFilter(array(
array('attribute'=>'ean','eq'=>'' . $ean['ean_l'] . ''),
));
echo 'ean_l: ' . $ean['ean_l'] . '<br>';
foreach ($collection as $product) {
echo $product['entity_id'];
}
}
So here's how it works:
We select an attribute (ean).
We get a list of all ean numbers from the database.
We loop through the list and compare any product with the ean number.
Then we loop through the collection and get the id of the corresponding product.
Yet, all $product['entity_id']'s are 273. It is correct that the entity_id is 273, but there is also product 274 with a corresponding ean number.
Here is the result from the script (it's alot more):
So why is this? Because in my reasoning, it changes the ean_l every loop and it equalizes it with the attribute values.
And then it should change the collection, right?
So shouldn't it at least show 274 at some point?
This question is not especially for Magento programmers, but other programmers can help too, so I figured to post it on SO.
Magento comes with powerfull filtering and queries into collections. If that doesn't satisfy, you can always extend with custom queries into getSelect function. Some info here.
Using addFieldToFilter into that foreach will filter the remaining values after another iterated filtering. So it's not good.
$allean = array("of", "ean", "values", "needed", "for", "filtering");
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ean');
//addAttributeToFilter for EAV collections
$collection->addAttributeToFilter('ean', array('in' => $allean)); //not addFieldToFilter
$collection->getColumnValues('entity_id');
var_dump($collection); //will output an array of product_ids
Alternative, if you want to group by ean values you should remove getColumnValues and run group command.
You can find additional info here.
Or you can just remove getColumnValues, start a foreach($collection as $product) and group manually or do what you want with those filtered products.
Related
I want to optimize my query as it is taking long to run with current eloquents. I have two table, toys and product.
From each product one is reserved as sample of toy if not than it has to be updated as sample by the query so what i'm doing right now is below.
$toywithsample=product::select('toyid')->groupBy('toyid')->where('sample','yes')->get();
Above code is to get id of all the product with which have their one sample from in its product
$toywithoutsamples=toy::select('id')->whereNotIn('id',$toywithsample)->get();
Above code is to get id of all product which have no sample toy in
foreach($toywithoutsamples as $toywithoutsample){
$product=product::where('toyid',$toywithoutsample->id)
->where('sample','sale')->limit(1)
->update(['sample'=>'yes']);
}
Below is table structure
toy table
id,name,
product
id, toyid,sample
$toys_ids_with_sample = Product::where('sample', 'yes')->get()->pluck('toyId');
// get the products grouped by toyId.
$products = Product::whereNotIn('toyId', $toys_ids_with_sample)->where('sample', 'sale')->get()->groupBy('toyId');
// get the product ids whose sample field you want to change to
// yes.
$update_product_ids = [];
foreach($products as $toyId => $products){
// We will only pick the first one, as we have to change just 1.
array_push($update_product_ids, $products->first()->id);
}
Product::whereIn('id', $update_product_ids)->update(['sample' => 'yes']);
This reduces the total number of queries.
I am working on a custom Magento Extension.
Here is how I take all customers in a customer group:
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*');
foreach($customers as $customer)
{
$email=$customer->getEmail();
$CustomerPhone = $customer->getPrimaryBillingAddress()->getTelephone();
$CustomerName = $customer->getName();
$CustomerEmail = $customer->getEmail();
}
This how I get information about the users in a specific customer group.
How I can get all the users ever paid or complete (for example) an order?
This is 90% of the way there:
<?php
require_once '<path_to_magento_root>/app/Mage.php';
Mage::app('default');
$customers = Mage::getResourceModel('reports/customer_collection')
->setPage(0,10)
//->addAttributeToFilter('orders_count', array('gt' => 0))
->addOrdersStatistics();
foreach ($customers as $c) {
echo $c->getId().' - '.$c->getEmail().': '.$c->getOrdersCount()." orders, average amount ".$c->getOrdersAvgAmount().", sum amount ".$c->getOrdersSumAmount().PHP_EOL;
}
The missing 10% is that this lists all customers, and their order information, rather than only ones with at least one order (which will include in-progress orders - the addOrdersStatistics() includes any orders that aren't canceled).
I have that commented line in there, //->addAttributeToFilter('orders_count', array('gt' => 0)), because I thought that should do it, but it appears to be doing nothing at all. Still, I figured I'd put this much up at least, because maybe it's at least a step in the right direction.
Of course, you also could just loop through every order, and build an array of customers that fit your criteria, but that's probably going to be much, much slower than using Magento's reports models like this. As a last resort, though, it'd work. So would querying the database directly, for that matter.
Try following solution this should work for you.
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*');
$customers->joinTable(
array('sales/order'),
'customer_email=email',
array('*'),
null,
'right'
);
// print_r($customers->getData());
$data = $customers->getData();
foreach($data as $d)
{
//print_r($d); // print this to see the available fields
echo $d[customer_email]; //get the desired information
echo "<br>";
}
I am creating custom emails to be sent to customers wanting to share their cart with others. So far, I have each product's quantity, SKU, price, path (node/XYZ), and title. The last item I need in the email is the product's image path.
I found all the other information with the following:
$order = commerce_cart_order_load($user->uid);
foreach($wrapper->commerce_line_items as $d => $line_item_wrapper) {
$sku = $line_item_wrapper->line_item_label->value();
//...
Printing out the following I was able to see a protected "data" property for the wrapper object:
print_r($line_item_wrapper->commerce_product);
Then, I tried finding the getter method for the field_image property with the following:
print_r($line_item_wrapper->commerce_product->getPropertyInfo('field_image');
I ended up here with entity_metadata_field_verbatim_get() but I don't know what parameters to pass. Also, in the last print statement above I didn't see anything else of value.
I'm wondering if I need to query for this data, and what table / columns to query for? Or maybe use something like node_load()? However, i'm not finding it too easy to find the node ID from the line item wrapper.
I was able to solve the above problem with this code:
$order = commerce_cart_order_load($user->uid);
$wrapper = entity_metadata_wrapper('commerce_order', $order);
$result = array();
foreach($wrapper->commerce_line_items as $d => $line_item_wrapper) {
$product = array();
$product['quantity'] = $line_item_wrapper->quantity->value();
$product['sku'] = $line_item_wrapper->line_item_label->value();
$product['path'] = $line_item_wrapper->commerce_display_path->value();
$product['price'] = $line_item_wrapper->commerce_unit_price->amount->value();
$product['title'] = $line_item_wrapper->commerce_product->title->value();
$product['image'] = $line_item_wrapper->commerce_product->field_image->value();
$product['image'] = $product['image'][0]['filename'];
array_push($result, $product);
}
I have to say, finding all these discrete functions was quite difficult. I did not find any clear documentation about Drupal Commerce metadata_wrappers. If anyone could provide further information I'd love to take a look.
In general, I used a lot of print_r(); to find these values.
I need to generate a table of filterable attributes with values of current product, something like
color - 3
size - 5
x - y
...
In my view.phtml
Problem is: my shop will have many attribute sets, and attributes can change. So I can't get attributes value by name.
I get an attribute sets code of current product, and retrieve all attributes of this set. But I don't know how filtered it by only filterable attributes?
Or maybe someone know simpler way to do this?
Thank you, and sorry for my English
Roman, you can get all filterable attribute by below code. Modify/add your condition to get the specific data accordingly.
$collection = Mage::getResourceModel('catalog/product_attribute_collection');
$collection
->setItemObjectClass('catalog/resource_eav_attribute')
->setOrder('position', 'ASC');
$collection->addIsFilterableFilter();
$result = array();
foreach ($collection as $attribute) {
$result[] = array('value' => $attribute->getAttributeCode(), 'label'=>$attribute->getFrontendLabel());
}
i want to filter and paginate a product collection. everything is fine - except pagination. im just getting the whole collection back, instead of 3 items for the first page.
//fetch all visible products
$product_collection = Mage::getModel('catalog/product')->getCollection();
//set wanted fields (nescessary for filter)
$product_collection->addAttributeToSelect('name');
$product_collection->addAttributeToSelect('description');
$product_collection->addAttributeToSelect('price');
$product_collection->addAttributeToFilter('visibility', array('neq' => 1));
//filter by name or description
$product_collection->addFieldToFilter(array(
array('attribute'=>'name','like'=>$sTerm),
array('attribute'=>'description','like'=>$sTerm)
));
//filter for max price
foreach ($product_collection as $key => $item) {
if($item->getPrice() >= $priceTo){
$product_collection->removeItemByKey($key);
}
}
//pagination (THIS DOESNT WORK!)
$product_collection->setPageSize(3)->setCurPage(1);
//TEST OUTPUT
foreach ($product_collection as $product) {
echo $product->getName().'<br />';
}
thanks for your support!
You are so close! Try moving that $product_collection->setPageSize(3)->setCurPage(1); line before the first foreach() iteration over the collection.
Magento collections are lazy-loaded. Until you directly load() them (or implicitly load them via a call to count() or foreach()) you can modify the collection properties which affect the underlying query (EDIT: see note below). Once the collection has been loaded explicitly or implicitly though you will only get the members of the _items property that have been set.
FYI you can call clear() to leave the original query-affecting properties (filters, sorters, limits, joins, etc) in place and then add further properties.
HTH
EDIT: Actually, adjusting query properties is always possible regardless of _items load state, but the effect won't be visible until the collection is regenerated.
Thanks #Ben! You gave me the right hint. Now it does work! Basically I'm creating another collection and filter this one by the ids of the already filtered items. Afterwards its easy to add pagination to that new collection. That's the working code:
//fetch all visible products
$product_collection = Mage::getModel('catalog/product')->getCollection();
//set wanted fields (nescessary for filter)
$product_collection->addAttributeToSelect('name');
$product_collection->addAttributeToSelect('description');
$product_collection->addAttributeToSelect('price');
$product_collection->addAttributeToFilter('visibility', array('neq' => 1));
//filter by name or description
$product_collection->addFieldToFilter(array(
array('attribute'=>'name','like'=>$sTerm),
array('attribute'=>'description','like'=>$sTerm)
));
//filter for max price
foreach ($product_collection as $key => $item) {
if($item->getPrice() >= $priceTo){
$product_collection->removeItemByKey($key);
}
}
//build id array out of filtered items (NEW!)
foreach($product_collection as $item){
$arrProductIds[]=$item->getId();
}
//recreate collection out of product ids (NEW)
$product_filtered_collection = Mage::getModel('catalog/product')->getCollection();
$product_filtered_collection->addAttributeToFilter('entity_id', array('in'=>$arrProductIds));
//add pagination (on new collection) (NEW)
$product_filtered_collection->setPageSize(3)->setCurPage(1);
//TEST OUTPUT
foreach ($product_filtered_collection as $product) {
echo $product->getName().'<br />';
}