Adding attribute options programmatically are not available for use immediately - magento

I'm creating Magento attribute options via a script, but I need to then be able to get the new ID and use it straight away in the same script.
At the moment it's not pulling the id through - if I kill the script and re-start it it picks up the created option and returns the ID, but not as part of the same script.
Here is the code I am using:
$attr = Mage::getModel('catalog/product')->getResource()->getAttribute($key);
if ($attr->usesSource()) {
$vattr_id = $attr->getSource()->getOptionId($value);
}else{
echo "No Source";
$vattr_id = false;
}
if($vattr_id){
return $vattr_id;
}else{
$attr_model = Mage::getModel('catalog/resource_eav_attribute');
$attr = $attr_model->loadByCode('catalog_product', $key);
$attr_id = $attr->getAttributeId();
$option['attribute_id'] = $attr_id;
$option['value'][$value][0] = $value;
$option['value'][$value][1] = $value;
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttributeOption($option);
$attr = Mage::getModel('catalog/product')->getResource()->getAttribute($key);
if ($attr->usesSource()) {
$vattr_id = $attr->getSource()->getOptionId($value);
echo "AttrID: $vattr_id";
}
}
Running this (with the required Mage::app() etc), creates the option, you can see it in the Magento back end, but the $vattr_id is NULL. If I reload the script, then it finds the attribute option in that first block as it should.
I guess it's something to do with how Magento is caching the models, but not sure where I need to look to clear these?

function getAttributeOptionId($attributeName, $attributeValue) {
/* #var $attribute Mage_Eav_Model_Entity_Attribute */
$attribute = Mage::getModel("eav/entity_attribute")->loadByCode("catalog_product", $attributeName);
// checking attribute code
if ($attribute->getId()) {
$source = $attribute->getSource();
$options = $source->getAllOptions();
// looking for existing id
foreach ($options as $optionValue) {
if ($attributeValue == $optionValue["label"]) {
return $optionValue["value"];
}
}
// making new option
$addOptionData = array(
"attribute_id" => $attribute->getId(),
"value" => array(array($attributeValue))
);
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttributeOption($addOptionData);
// getting new id
$attribute = Mage::getModel("eav/entity_attribute")->loadByCode("catalog_product", $attributeName);
$source = $attribute->getSource();
$options = $source->getAllOptions();
foreach ($options as $optionValue) {
if ($attributeValue == $optionValue["label"]) {
return $optionValue["value"];
}
}
}
return null;
}
echo getAttributeOptionId("brand", "Intel");

Related

joomla - router change url when getting the name of product

I have build my own component in joomla and client wants now a friendly urls f.e
website.com/someplace/{product-id}-{product-name}. So i Build my own router like this.
function componentBuildRoute(&$query)
{
$segments = [];
if (isset($query['view'])) {
$segments[] = "szkolenie";
unset($query['view']);
}
if (isset($query['product_id'])) {
$productName = JFilterOutput::stringURLSafe(strtolower(getProductName($query['product_id'])));
$newName = $query['product_id'] . '-' . $productName;
$segments[] = $newName;
unset($query['product_id']);
}
return $segments;
}
and parse route function
function componentParseRoute($segments)
{
$app = JFactory::getApplication();
$menu = $app->getMenu();
$item =& $menu->getActive();
$count = count($segments);
switch ($item->query['view']) {
case 'catalogue' : {
$view = 'training';
$id = $segments[1];
}
break;
}
$data = [
'view' => $view,
'product_id' => $id
];
return $data;
}
While on the end of buildroute function segments are ok I have exactly what I want that on the beginning of parse route I have something like
website.com/szkolenie/1-krakow <-- I dont know wtf is this krakow( I know it is city i Poland) but still where is it get from ? The getProductName function implementation is
function getProductName($productId)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('#__component_training.id as id, #__component_product' . name)
->from($db->quoteName('#__component_training'))
->where('#__s4edu_product.product_id = ' . $productId)
->leftJoin('#__component_product ON
#__component_training.product_id=#__component_product.product_id');
$training = $db->loadObject();
return trim($training->name);
}
So taking all this into consideration I think that something is happening between the buildRoute and parseRoute, something what filters the $segment[1] variable, but how to disable that and why is it happening ?
P.S
Please do not send me to https://docs.joomla.org/Joomla_Routes_%26_SEF
I already know all the tutorials on joomla website which contains anything with sef.
P.S.S
It is built on joomla 3.7.0
You do not have a product named "krakow" ?
If not you can try to remove the $productName from the build function, just to check if this "krakow" is added automaticaly or it's from the getProductName() function.
Also i noticed that you have an error i guess in the function getProductName()
->where('#__s4edu_product.product_id = ' . $productId)
It's should be
->where('#__component_product.product_id = ' . $productId)

Convert magento admin quote into a multi address order

Say I have a quote from the admin create order with all the products already entered, how could I go about writing some code to add multiple shipping addresses and assign the item to the address.
Ive got some code working, based loosely off the frontend multiship model. The problem I'm having is adding the multiple address and assigning the items to the quote. If I have a standard quote, how can I add the multiple addresses?
I've already tried :
$address = Mage::getModel('customer/address')->load($addressID);
$quote->addShippingAddress($address);
Which seems to only hold one address
The whole function:
public function createMultiOrders() {
// print_r($_POST);
$items = $_POST['item'];
$itemsByAddress = array();
$billingInfo = array();
$session = Mage::getSingleton('adminhtml/session_quote');
$quote = $session->getQuote();
//first we are reorganizing the data provided by javascript into an array based on address ID's
foreach ($items as $key => $item) {
$addID = $item['addressID'];
$itemID = $key;
$qty = $item['qty'];
$itemsByAddress[$addID][] = array('itemID' => $itemID, 'qty' => $qty);
}
// print_r($itemsByAddress);
//now that we have an array of items, seperated by which addressid they goto, we can create the order for each address
foreach ($itemsByAddress as $addressID => $items) {
$address = Mage::getModel('customer/address')->load($addressID);
$quote->addShippingAddress($address);
echo"<br/>address id is $addressID, items are: <br/>";
foreach ($items as $item) {
// $address->addItem($_item);
///add items to order
// echo"id before is $item<br/>";
$itemID = explode('-_', $item['itemID']);
$itemID = $itemID[0];
$qty = $item['qty'];
echo "itemid is $itemID, qty is " . $qty . " <br/><br/><br/><br/>";
}
}
//print_r(get_class_methods($quote));
$shippingAddresses = $quote->getAllShippingAddresses();
try {
foreach ($shippingAddresses as $address) {
$order = $this->_prepareOrder($address);
$orders[] = $order;
Mage::dispatchEvent(
'checkout_type_multishipping_create_orders_single', array('order' => $order, 'address' => $address)
);
}
foreach ($orders as $order) {
$order->place();
$order->save();
if ($order->getCanSendNewEmailFlag()) {
$order->sendNewOrderEmail();
}
$orderIds[$order->getId()] = $order->getIncrementId();
}
Mage::getSingleton('core/session')->setOrderIds($orderIds);
Mage::getSingleton('checkout/session')->setLastQuoteId($quote->getId());
$quote->setIsActive(false)->save();
Mage::dispatchEvent('checkout_submit_all_after', array('orders' => $orders, 'quote' => $quote));
return $this;
} catch (Exception $e) {
Mage::dispatchEvent('checkout_multishipping_refund_all', array('orders' => $orders));
throw $e;
}
Ok I solved the issue and successfully was able to write a script to turn an ordinary admin order into a multi address order. One of the mistakes that messed with me the entire time was the way I loaded the admin quote:
I was loading the session like this
$session = Mage::getSingleton('adminhtml/session_quote');
and it should be
$session = Mage::getModel('adminhtml/session_quote');
Now, as far as assigning each of the quote items to an address, the final code looks like:
$address = Mage::getModel('customer/address')->load($addressID);
echo"<br/>address id is $addressID<br/>";
echo"quote address not set, adding shipping address <br/>";
$quoteAddress = Mage::getModel('sales/quote_address')->importCustomerAddress($address);
$quote->addShippingAddress($quoteAddress);
$quoteAddressItem = $quoteAddress->getItemByQuoteItemId($quoteItem->getId());
if ($quoteAddressItem) {
echo"increasing item quantitiy for quote address<br/>";
// $quoteAddressItem->setQty((int) ($quoteAddressItem->getQty() + $qty));
} else {
echo"setting customer id for quote item<br/>";
$quoteItem->setCustomerAddressId($quoteAddress->getCustomerAddressId());
echo"adding item to quote address<br/>";
$quoteAddress->addItem($quoteItem)->setQuote($quote);
echo"adding item to quote collection<br/>";
if (!$quoteAddress->getItemsCollection()->getItemById($quoteItem->getId())) {
$quoteAddress->getItemsCollection()->addItem($quoteItem)->save();
}
$quoteAddress->setCollectShippingRates(TRUE);
$quoteAddress->collectShippingRates();
$quoteAddress->save();
$quoteItem->save();
$quote->save();
}

CakePHP serializing objects

I'm stuck with the following problem:
I have a class CartItem. I want to store array of objects of CartItem in session (actually i'm implementing a shopping cart).
class CartItem extends AppModel{
var $name = "CartItem";
var $useTable = false;
}
I tried this:
function addToCart(){
$this->loadModel("Cart");
$this->layout = false;
$this->render(false);
$cart = array();
$tempcart = unserialize($this->Session->read("cart"));
if(isset($tempcart)){
$cart = $tempcart;
}
$productId = $this->request->data("id");
if(!$this->existsInCart($cart, $productId)){
$cartItem = new Cart();
$cartItem->productId = $productId;
$cartItem->createdAt = date();
$cart[] = $cartItem;
$this->Session->write("cart", serialize($cart));
echo "added";
}
else
echo "duplicate";
}
I think I'm writing these lines wrong:
$tempcart = unserialize($this->Session->read("cart"));
$this->Session->write("cart", serialize($cart));
as I'm not getting data from the session.
You are trying to add the whole Cart object to the session.
You should just add an array, like
$cart[] = array(
'productId' => $productId,
'createdAt' => date('Y-m-d H:i:s')
);
If you need to add an object to a session, you can use __sleep and __wakeup magic functions but I think in this case it's better to just add only the product id and date to the session.

Magento sets null value for non-selected attribute value in admin. It affects the frontend display. How to deal with it?

I've created a new attribute (type: dropdown) that is not a required field.
At this moment, every product shows in the frontend "my attribute: n/a".
After save anything in some product, magento write a null value inside catalog_product_entity_int table for this attribute.
But in the frontend the attribute now appear as "my attribute: No" instead of "N/A".
It looks like a bug, since I didn't touch in the attribute while editing the new product.
Is there a way to deal with it or to apply some rule in my phtml?
Actually this is not a bug. It's a feature.
N/A is displayed when there is no record in the table catalog_product_entity_int for that attribute.
When you add an attribute there are no values for that attribute for any product, but as soon as you save a product that has that attribute, a null value is inserted in the table (as you stated). So no value is different from null value.
All the magic happens here Mage_Catalog_Block_Product_View_Attributes::getAdditionalData().
These are the lines that interest you:
if (!$product->hasData($attribute->getAttributeCode())) { // no value in the database
$value = Mage::helper('catalog')->__('N/A');
} elseif ((string)$value == '') { // empty value in the database
$value = Mage::helper('catalog')->__('No');
}
If you want to change anything override this method.
If you change anything you might want to take a look at Mage_Catalog_Block_Product_Compare_List::getProductAttributeValue().
The same system is used for displaying attribute values in the compare products list.
I've ended up to create 2 observers... One that overrides getValue from Mage_Eav_Model_Entity_Attribute_Frontend_Default and other to override getAdditionalData in Mage_Catalog_Block_Product_View_Attributes as follows:
<?php
class Namespace_Module_Model_Entity_Attribute_Frontend_Default extends Mage_Eav_Model_Entity_Attribute_Frontend_Default{
public function getValue(Varien_Object $object)
{
$value = $object->getData($this->getAttribute()->getAttributeCode());
if (in_array($this->getConfigField('input'), array('select','boolean'))) {
$valueOption = $this->getOption($value);
if (!$valueOption) {
$opt = Mage::getModel('eav/entity_attribute_source_boolean');
$options = $opt->getAllOptions();
if ($options && !is_null($value)) { //added !is_null
foreach ($options as $option) {
if ($option['value'] == $value ) {
$valueOption = $option['label'];
}
}
}
}
$value = $valueOption;
} elseif ($this->getConfigField('input') == 'multiselect') {
$value = $this->getOption($value);
if (is_array($value)) {
$value = implode(', ', $value);
}
}
return $value;
}
}
and
<?php
class Namespace_Module_Block_Product_View_Attributes extends Mage_Catalog_Block_Product_View_Attributes
{
public function getAdditionalData(array $excludeAttr = array())
{
$data = array();
$product = $this->getProduct();
$attributes = $product->getAttributes();
foreach ($attributes as $attribute) {
if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) {
$value = $attribute->getFrontend()->getValue($product);
if (!$product->hasData($attribute->getAttributeCode()) || (string)$value == '') { //modified
$value = Mage::helper('catalog')->__('N/A');
} elseif ($attribute->getFrontendInput() == 'price' && is_string($value)) {
$value = Mage::app()->getStore()->convertPrice($value, true);
}
if (is_string($value) && strlen($value)) {
$data[$attribute->getAttributeCode()] = array(
'label' => $attribute->getStoreLabel(),
'value' => $value,
'code' => $attribute->getAttributeCode()
);
}
}
}
return $data;
}
}

get the values of custom options

I'm trying to alter a price based on some custom options set. Therefore I'm trying to get the value a customer has entered, not the default values set in the backend. To do this I'm using the event catalog_product_get_final_price used in Mage_Bundle_Model_Product_Price. I have registered the following observer:
public function observer_callback($evt_obs)
{
$event = $evt_obs->getEvent();
$data = $event->getData();
/* #var $collection Mage_Catalog_Model_Resource_Product_Collection */
$collection = $data['collection'];
$items = $collection->getItems();
/* #var $item Mage_Catalog_Model_Product */
foreach ($items as $item) {
if ( $item->getName() == 'Bundel Test2') {
$options = $item->getCustomOptions();
/* #var $option Mage_Catalog_Model_Product_Option */
foreach ($options as $option) {
// Here I'm trying to get the value given by the user/customer
var_dump($option->getData());
}
}
}
return $this;
}
It is a custom option from a bundle type. So the product can't be configurable.
I'm new to magento so I'm probably missing something.
Can anyone help me?
Hope this piece of code can help you:
public function productFinalPrice($observer){
$product = $observer->getEvent()->getProduct();
$productType=$product->getTypeID();
if($productType == 'your_product_type')
{
$option = $product->getCustomOptions();
$searchedOption = null;
//search for your option;
foreach ($product->getOptions() as $o) {
if($o->getTitle()=="your_attribute_title" && $o->getType()=="your_type_of_option(eg. area"){
$optionId = $o->getOptionId();//got your searched optionId
break;
}
}
foreach($option as $key => $o) {
if($key == "option_".$optionId) {
$searchedOption = $o;
//here you get the option object with the values in it
}
}
$articleNumber = $searchedOption->getData('value'); // getthe value of your option
//calculate final price like you need it
$product->setFinalPrice($finalPrice);
}
return $this;
}
best regards

Resources