create a new object inside of a loop in php - php

I have an array of Product IDs and want to get the product information by calling the Product class. I have tried adding it in a foreach loop and get a fatal error saying Object of class Product could not be converted to string. This is what I have tried.
$productIDs = Db::getInstance()->executeS("SELECT id_product FROM wtop_product ORDER BY position ASC");
$products = '';
foreach($productIDs as $productID)
{
$products .= new Product($productID['id_product'], false, '1');
}
Since this ouputs an error obviously it is not the correct way to handle this situation. What i'm not sure of is how to pass the array of product IDs to the new Product call and get an output of each of those products.

Store objects in array:
$products = array();
foreach($productIDs as $productID) {
$products[$productID['id_product']] = new Product($productID['id_product'], false, '1');
}
print_r($products);

Related

add new element in laravel collection object

I want to add new element in $items array, I don't want to use joins for certain reasons.
$items = DB::select(DB::raw('SELECT * FROM items WHERE items.id = '.$id.' ;'));
foreach($items as $item){
$product = DB::select(DB::raw(' select * from product
where product_id = '. $id.';' ));
$item->push($product);
}
What should I do?
It looks like you have everything correct according to Laravel docs, but you have a typo
$item->push($product);
Should be
$items->push($product);
push method appends an item to the end of the collection:
I also want to think the actual method you're looking for is put
$items->put('products', $product);
put method sets the given key and value in the collection
As mentioned above if you wish to add as a new element your queried collection you can use:
$items = DB::select(DB::raw('SELECT * FROM items WHERE items.id = '.$id.' ;'));
foreach($items as $item){
$product = DB::select(DB::raw(' select * from product
where product_id = '. $id.';' ));
$items->push($product);
// or
// $items->put('products', $product);
}
but if you wish to add new element to each queried element you need to do like:
$items = DB::select(DB::raw('SELECT * FROM items WHERE items.id = '.$id.' ;'));
foreach($items as $item){
$product = DB::select(DB::raw(' select * from product
where product_id = '. $id.';' ));
$item->add_whatever_element_you_want = $product;
}
add_whatever_element_you_want can be whatever you wish that your element is named (like product for example).
If you want to add item to the beginning of the collection you can use prepend:
$item->prepend($product, 'key');
If you want to add a product into the array you can use:
$item['product'] = $product;
I have solved this if you are using array called for 2 tables. Example you have,
$tableA['yellow'] and $tableA['blue'] . You are getting these 2 values and you want to add another element inside them to separate them by their type.
foreach ($tableA['yellow'] as $value) {
$value->type = 'YELLOW'; //you are adding new element named 'type'
}
foreach ($tableA['blue'] as $value) {
$value->type = 'BLUE'; //you are adding new element named 'type'
}
So, both of the tables value will have new element called type.
This is what i would do...
$items = Item::find($id);
foreach($items as $item){
$product = Product::find($id);
$item->product = $product;
}
This would assign $product to each $item

How to use a for loop on a collection pulled from Magento

im trying to use a for loop on products i pulled from Magento.
And it crashes when i want to use the index on a product in the loop.
$collection = Mage::getModel('catalog/product')->getCollection();
$collectionLength = count($collection);
for($j = 0; $j < $collectionLength; $j++)
{
$productFromStore = $collection[$j];//it crashes on this line of code
$sku = $productFromStore->getSku();
}
but when i use a foreach loop i can reach all the products.
foreach($collection as $product)
{
// this code works fine
$sku = $product->getSku();
}
Can someone explain what is going wrong and why?
Thanks.
First of all, You trying to iterate collection object as array
Here is Error :
Fatal error: Cannot use object of type
Mage_Catalog_Model_Resource_Product_Collection as array
, second for loop isn't the best way to iterate collections better is foreach loop becacuse for loop need to count of array emelents foreach dont need it.
Third, the best way is to use magento resource iterator.
Mage::getSingleton('core/resource_iterator')
->walk(
$query->getSelect(),
array(array($this,'callbackFunction')));
here is an example:
public function someGetCollectionMethod()
{
$products = Mage::getModel('catalog/product')->getCollection();
Mage::getSingleton('core/resource_iterator')
->walk(
$products->getSelect(),
array(array($this, 'productsCallback')));
}
public function productsCallback($args)
{
$product = Mage::getModel('catalog/product');
$prod = $product->load($args['row']['entity_id']);
Zend_Debug::dump($prod->getSku());
}
Happy coding,
Adam
Collection classes in Magento's ORM ultimately subclass Varien_Data_Collection which implements IteratorAggregate; this is why you are able to work with the collection object in an array-like fashion (i.e. foreach), but not have it work for the for loop. For one thing, dThere is no direct key-based access to the elements inside the object (_items array members) - unfortunate, given that the key for the _items array is based on the row ID.
Bottom line: working with collection items in a for loop is not very easy, not when compared to the ease of working with collection items via IteratorAggregate and all of its related goodies.
Here's an example of both. If you have an overarching need to work with the collection's items directly then you can use $collection->getItems(), but again realize that the _items array keys may not be sequential as they are based on the data. Also, note that you need to add the name attribute value to collections stored using Magento's EAV pattern:
<?php
header('Content-Type: text/plain');
include('app/Mage.php');
Mage::app();
$collection = Mage::getResourceModel('catalog/product_collection');
$collection->addAttributeToSelect('name');
//for loop - not as much fun
for ($j=0;$j<count($collection);$j++) { //count() triggers $collection->load()
$items = $collection->getItems();
$item = current($items);
echo sprintf(
"%d:\t%s\t%s\n",
$k,
$item->getSku(),
$item->getName()
);
next($items); //advance pointer
}
//foreach - a bit better
foreach ($collection as $k => $product) {
echo sprintf(
"%d:\t%s\t%s\n",
$k,
$product->getSku(),
$product->getName()
);
}
And just in case you are wondering: Performance of FOR vs FOREACH in PHP
$array = array(
"foo" => "bar",
"bar" => "foo",
);
This type of array cannot be accessed by indexes you have to use,
$array["foo"];
If the keys are unpredictable you have to use
`foreach
I'm no expert in magento, but perhaps it's because the collection has different keys other than just numbers? Try printing out the collection with print_r to see what keys does the object have.
If you need iterations with numbers, you can always do something like that:
$i=0;
foreach($collection as $product)
{
$sku = $product->getSku();
$i++;
}
EDIT: Anyway, it seems collections aren't regular arrays, so you cannot use them the way you tried.
That's because you are sending an empty value to the getSku function.
<?php
$collection=array("book1"=>"bat","book2"=>"cat");
$collectionLength = count($collection);
for($j = 0; $j < $collectionLength; $j++)
{
$productFromStore = $collection[$j];
echo $productFromStore; //prints nothing !
}
foreach($collection as $var)
{
echo $var; //prints batcat
}
In magento collection return in form of object. use below code fetch SKU and NAME. Or use print_r($collection->getData()) to get data in array Key=>value format.
foreach($collection as $productCollection){
$sku = $productCollection->getSku();
$name = $productCollection->getName();
}

Get manufacturers of all products in a category from non-product page

I made the following method in custom Magento controller to retrieve all the manufacturers in the specified category. The module is made as a service to get the data for ajax calls.
I made a number of methods like this and all are executed on my local server in the range of 5-7 seconds. This one takes 14 seconds to execute on local server.
Can you help me to find a bottleneck here:
public function subcategoryAction() {
$storeId = Mage::app()->getStore()->getStoreId();
// Subcategory ID passed with a GET method
$sub = $this->getRequest()->getParam('subcategory');
if ($sub) {
// Querying to get all product ID's in the specified subcategory
$product_ids = Mage::getResourceModel('catalog/product_collection')
->setStoreId($storeId)
->addAttributeToFilter('status', array('eq' => '1'))
->addAttributeToFilter('visibility', 4)
->addCategoryFilter(Mage::getModel('catalog/category')
->load($sub))->getAllIds();
$product = Mage::getModel('catalog/product');
// Load all the product models by their ID's
foreach ($product_ids as $id) {
$product->load($id);
$manufacturers[] = $product->getAttributeText('manufacturer');
}
// Getting unique values of manufacurers, just like array_unique
$manufacturers[$product->getAttributeText('manufacturer')] = $product->getAttributeText('manufacturer');
// Echoing default option value
echo "<option value='all'>BRAND/MAKE</option>";
// Echoing and formatting manufacturers for a dropdown
foreach ($manufacturers as $manufacturer) {
if ($manufacturer != "") {
echo "<option value='" . $manufacturer . "'>" . $manufacturer . "</option>";
}
}
}
}
Accepted #Mischa Leiss suggestion, changed this messy unique values code:
$manufacturers=array_flip(array_flip(array_reverse($manufacturers,true)));
to his code:
$manufacturers[$product->getAttributeText('manufacturer')] = $product->getAttributeText('manufacturer');
SOLUTION
This is the quickest solution, all thanks to #Mischa
$products = Mage::getResourceModel('catalog/product_collection')
->setStoreId($storeId)
->addAttributeToSelect('manufacturer')
->addAttributeToFilter('status', array('eq' => '1'))
->addAttributeToFilter('visibility', 4)
->addCategoryFilter(Mage::getModel('catalog/category')
->load($sub));
Takes only about 2 seconds.
A. the bottleneck is that you explicitly load each model instead of fetching the data straight from the collection itself - dont get the ids but a collection of products and iterate over it.
B. next thing is, why dont you just add the manufacturer attribute id as array key, so you dont need to array flip.
$manufacturers[$product->getManufacturer()] =
$product->getAttributeText('manufacturer');
C. even better would be to build some custom source model to simply do a smarter sql query.
I assembled a little join series (used color attribute) to get the label/value pair via a product collection:
$collection = Mage::getModel('catalog/product')->getCollection();
//get the color attribute joined
$collection->addAttributeToSelect('color', 'left');
//join the label from the attribute option table
$collection->joinField('color_label', 'eav_attribute_option_value', 'value', 'option_id=color');
//group for uniqueness reset the columns and fetch what we want
$collection->getSelect()->group(array('color_label'));
$collection->getSelect()->reset(Zend_Db_Select::COLUMNS);
$collection->getSelect()->columns(array('color_label' => 'at_color_label.value', 'color_id' => 'at_color_label.option_id'));
Good luck!

Module that edits existing product names in magento?

Please I am trying to create a module in magento that edits the products' name by concatenating the existing product names with randomly generated numbers.
$model = Mage::getModel('catalog/product') ->load(1111) //getting
product model
$collection = $model->getCollection(); //products collection
foreach ($collection as $product) //loop for getting products
{
$model->load($product->getId());
$pname = $product->getName(); 
$this->model = Mage::getModel('catalog/product');
$new_name = $pname.' '.rand(1000,5000);
$this->model->setName($new_name);
}
This is my code, I am trying to create a module to achieve this functionality without editing the core files or using the admin panel.
Sorry but your code is ugly.
If you want to use collection (that is a good way to access data from a list of object) you must not use a ->load() (very expensive and should be used only when accessing data for a single object, like a product page)
Try this code instead :
$collection = Mage::getModel('catalog/product')->getCollection(); //products collection
$collection->addAttributeToSelect('name'); //retrieve only product name (optimising SQL)
foreach ($collection as $product) //loop for getting products
{
$pname = $product->getName();
$new_name = $pname.' '.rand(1000,5000);
$product->setName($new_name);
$product->save(); // you missed that
}
If you have a high number or product, you could also make a single SQL query with the SQL CONCAT() function ...
class Digital_GoogleMpn_Model_Observer {
public function googleMpn(Varien_Event_Observer $observer)
{
$product = $observer->getEvent()->getProduct();
$pname = $product->getName();
$google_mpn = rand(1000,5000);
$new_name = "{$pname}.' '.{$google_mpn}";
$product->setName($new_name);
$product->save();
} }

How To Get Sub Categories in Magento ?`

I am playing with magento's home page where I have created a tab Which Shows all the categories including Root, categories, and Sub Categories (In One Tab). Now I want to Show Only Main Categories( Whose Parent Is Root) in main Tab And under Each Category I want to List Their respective Sub Categories. I wrote The following Code to achieve a part of this,
MODEL CLASS
public function getsubCategory($parent)
{
$subcategoryCollection = Mage::getModel('catalog/category')
->getCollection()
->addAttributeToFilter('parent_id', $parent);
return $subcategoryCollection;
BLOCK CLASS
protected function b4Html_subcategory($parent)
{
$catModel = Mage::getModel('Pragtech_Sweet/category');
$mysubCategory = $catModel->getsubCategory($parent);
$this->mysubCategory = $myCategory;
return $mysubCategory;
}
TEMPLATE FILE
$obj = new Pragtech_Sweet_Block_Category();
$collection = $obj->b4Html();
foreach ($collection as $category)
{
$name = $category->getName();
$parent = $category->getParent_id();
foreach ($obj->b4Html_subcategory($parent) as $subcategory)
{
$subname = $subcategory->getName();
//Here Will Go Ther Code For Sub Categories
}
but it doesn't work.. I am unable to understand where I am doing wrong... Can anyone help me out
Do this instead :
Mage::getModel('catalog/category')->load('23')->getChildrenCategories();
and iterate over the result.
and that's how i found it out:
$object = Mage::getModel('catalog/category');
print_r(get_class_methods($object));
print_r($object->load('23')->getChildrenCategories()->toArray());
Here's another way to do this, if you don't want to mess with the treeModel stuff, or want more control how categories are loaded:
function getCategoryTree($root_category_name)
{
$categories = Mage::getModel('catalog/category')->getCollection()
->addAttributeToSelect("*")
->addFieldToFilter("Name",array("eq"=>$root_category_name));
$stack = array();
$category = $categories->getFirstItem()->getData();
$categories=array();
array_push($stack, $category);
//regular recursion is boring, let's do a stack
while(count($stack) > 0)
{
$category = array_pop($stack);
array_push($categories, $category);
$children = Mage::getModel('catalog/category')->getCollection()
->addAttributeToSelect("*")
->addFieldToFilter("parent_id",array("eq"=>$category['entity_id']))
->addAttributeToSort("position","desc");
foreach ($children as $child)
{
array_push($stack, $child->getData());
}
}
return $categories;
}
This will give you an array of categories representing the full category tree rooted at the top category with the name "Some Category Name", in order, with all of the category data. Tune this to only select the specific fields you need, instead of "*".
This technique can give you finer grained control of the loading of the category tree, and with how you want the data structured afterwards. For example, you could trivially modify this to do a hierarchical tree instead of a flat array and then serialize that to a JSON object to send to the client.
Add whatever filters you like (active, etc...) at whatever level you like to get even more control.
iterate through this object
Mage::getModel('catalog/category')
->getCollection()
->addAttributeToSelect('*')
->getItems();

Categories