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();
} }
Related
I have a persistent problem with all my project and I need help understanding how to make it work.
In my view =
URL = mysite.com/product/40 so here the product ID is 40
On the view I am doing a foreach loop to show all merchants that have this product. we have many merchants having many products so it is a many to many relationship.
Now on my controller
$product = Product::find($id); // to find the product
$users = $product->users; // here the user is the merchant that have the product
$store = Store::where('user_id', $user->id)->value('social');
Here i get the error :
Trying to get property of non-object
So I do want to access the store of each of the merchants in the controller how do I do this ? Because now $user is a collection.
Please first verify if the store is giving object or not by using var_dump. After that you can have a look into https://laravel.com/docs/5.6/queries for more details.
1) Firstly you can use Injection to avoid this line: $product = Product::find($id);
public function your_controller_methon(Product $product) {}
Laravel will automatically do the trick for you and $product will already contain Product object.
2) If you have relationship, you should do something similar to this:
$product->stores - to retrieve all stores which contains particular product in product_id column. And you could do: $product->stores()->pluck('social'); to retrieve list of socials from all merchants which have particular product.
About relationships you could read here: https://laravel.com/docs/5.7/eloquent-relationships
You can refactor your code to use the whereIn() query builder method since you have many users to a product. You will have something like:
$product = Product::find($id); // to find the product
$users = $product->users->pluck('id');
$stores = Store::whereIn('user_id', $users->all())->value('social');
This mean your $stores variable will contain those stores owned by the users.
PS: Be sure to check if $users is not empty or null so you don't encounter unexpected errors
According to you code, Here $user is a single value, not a collection.
Change:
$store = Store::where('user_id', $user->id)->value('social');
To
$store = Store::where('user_id', $user);
It will works.
To make the $user as a collection, execute such query so that it will return array such as:
$product = Product::find($id);
$user = Product::where('user', $product->user)->get();
This will return the collection of users of this product.
Then execute foreach loop:
foreach($user as $rowdata){
$store = Store::where('user_id', $rowdata->id)->get();
}
You should try this:
$product = Product::find($id);
$user = Product::where('user', $product->user)->get();
foreach($user as $rowdata){
$store = Store::where('user_id', $rowdata->id)->get();
}
I'm in a controller for Laravel 5.2 and am trying to iterate through an eloquent collection of invoice_items, which would translate to something like order items. So, the invoice would act as the order, have it's ordered items (invoice_item), and the invoice_items would list all of the products ordered (product).
Here's what I have:
$id = $value; //from param
$invoice = Invoice::where('id', $id)->get();
$invoice_items = Invoice_item::all()->where('invoice_id', $invoice[0]->id);
$contact = Contact::where('id', $invoice[0]->contact_id)->get();
foreach($invoice_items as $item) {
$products = Product::all()->where('id', $item->product_id);
}
I'm attempting to pull all of the products from that specific invoice (via invoice items), which in this specific case should be two, different products.
What's happening, is when I iterate through using that loop, it's adding the same product twice, whereas it should be adding each product once. Is my logic just wrong here? Or do I need to look at my relationships again or something?
Change your queries to:
$invoice = Invoice::where('id', $id)->get();
$invoice_items = Invoice_item::where('invoice_id', $invoice[0]->id)->get();
$contact = Contact::where('id', $invoice[0]->contact_id)->get();
foreach($invoice_items as $item) {
$products = Product::where('id', $item->product_id)->get();
}
An easier way may be to add a items relation to the InvoiceItems model. E.g.:
public function items()
{
$this->hasOne('Items');
}
Then you can get all the Items from Invoice_item using:
return $invoice_items->items;
You can also try:
$invoice = Invoice::where('id', $id)->get();
$invoice_items = Invoice_item::where('invoice_id', $invoice[0]->id)->get()->lists('product_id');
$contact = Contact::where('id', $invoice[0]->contact_id)->get();
$products = Product::whereIn('id', $invoice_items)->get();
Hopefully, $products will then contain a collection of products for that invoice. No need for a foreach loop.
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
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);
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!