Traverse ez-multioption attribute options in EZ Publish PHP-side - php

I need help to traverse all options in a multioption.
I use the Product-class with a new multioption-attribute called "product_properties". I need a function to check if the optionID the user chose on the front-end matches an option in the list, and return true if a match is found.
This way I can check if e.g. the user chose "Red" as the "Color" on a product.
In pseudo-code this is what I need:
Parameters: postedOptionID, currentObjectID
Fetch attribute "product_properties" (multioption) on object .
For each option for "Color" in "product_properties"
2.1 If postedOptionID == optionID
2.1.1 return true
Thanks

I finally found a way :)
$product_properties_name is the name of a class-attribute that's an 'ezmultioption'-datatype. In my case it's called 'product_properties' and is an attribute on the 'Product'-class.
First get all of the object's attribute:
$contentObjectAttributes = $contentObject->version($contentObject->attribute( 'current_version' ) )->contentObjectAttributes();
and then loop each and find 'product_properties':
// Loop all attributes of the object's class
foreach(array_keys($contentObjectAttributes) as $key)
{
$contentObjectAttribute = $contentObjectAttributes[$key];
$contentClassAttribute = $contentObjectAttribute->contentClassAttribute();
$attributeIdentifier = $contentClassAttribute->attribute("identifier");
// Get 'product_properties'-attribute
if ($attributeIdentifier == $product_properties_name)
{
// Get the multioption
$multioption_list = $contentObjectAttribute->content();
// Loop all multioption lists (Color, Make, Brand etc.)
foreach($multioption_list->attribute('multioption_list') as $index => $option)
{
// Loop through this multioption and get all options (if 'Color', get 'Blue', 'Red', 'Green' etc.)
foreach($option['optionlist'] as $option)
{
$optionValue = trim($option['value']);
// if there's a match on $optionValue, do something interesting...
}
}
}
}

Related

How to replace reference to element with its value?

in case of tl;dr: setting up array with references and then changing a copy of said array still preserves references and elements of all copies are changed at the same time. Need a workaround of replacing reference with the value that it points to.
I'm getting a complicated problem with using references in PHP Arrays :(
I have a flat array of unique elements with two properties: order and level.
Order represents element's order number from 1 to n in like table of contents way. Level represents which level "subchapter" the element is.
Example:
First brackets are element IDs which are random but unique:
[1][order:1][level:1]
----[7][order:2][level:2]
----[4][order:3][level:2]
---- ----[2][order:4][level:3]
[3][order:5][level:1]
[6][order:6][level:1]
----[5][order:7][level:2]
.
.
.
Remember, this is flat array of elements, above its just a visual representation.
Now I have tried to put them into array of form:
[1][children] => [
[7],
[4][children] => [
[2]
]
]
[3],
[6][children] => [
[5]
]
Which would represent a tree structure -ish..
I do this by first ordering them by order:
foreach($elements as $element){
$ordered_elements[$element['order']] = $element;
}
Then I shift each element under the correct parent:
foreach($ordered_elements as &$child){
if($child['level'] > 1){
$ordered_elements[$last_parent[$child['level']-1]]['children'][$child['content_id']] = &$child; // I think this is problematic line!!!
}
$last_parent[$child['level']] = $child['sort_order'];
}
Some of the elements stayed on root (first) level that shouldnt be there:
foreach($ordered_elements as &$child){
if($child['level'] == 1){
$ordered_elements[$child['content_id']] = $child;
}
unset($ordered_elements[$child['sort_order']]);
}
Now when this is done, the template array is ready. Now I start getting some data from query with element_id and user_id.
I want to set up a new table "users" that would have this previously made array for each user and I would be able to change its elements per user.
users[1]['elements'] = $ordered_elements;
users[2]['elements'] = $ordered_elements;
This function should return element by reference from user's own pool of elements, so we can change it directly into the users[x]['elements'][x]:
function &get_element_from_array(&$array, $searchValue){
$status = false;
foreach($array as $id => &$subtree) {
if ($id === $searchValue) {
return $subtree;
}
if (isset($subtree['children'])) {
$subsearch = &$this->get_element_from_array($subtree['children'], $searchValue);
if ($subsearch != false) {
return $subsearch;
}
}
}
return $status;
}
That means If i want to change element 5 from user 2 I need to call it like this:
$element = &get_element_from_array(users[2]['elements'], 5);
$element['visited'] = true;
This is where the problem occurs: I have just changed this element in user2 AND user1 array of elements.
I hope I didnt wrote this thing too long, was going for good explanation.

Drupal 7 Delete field collection for node

I just found a script to programatically delete a field collection to a specific node :
<?php
$node = node_load(1);
$field_collection_item_value = $node->field_page_collection1[LANGUAGE_NONE][0]['value']; // Take field collection item value.
entity_delete_multiple('field_collection_item', array($field_collection_item_value)); // Delete field collection item.
?>
Unfortunately as i see it , it only delete first field collection, I need to select which one i want to delete.
Here is my structure :
Multiple field collection who have : a reference to another node and two selects
I have the reference nid in the url so I can use it, but I don't have any idea how to select the right field collection with that.
Thanks
Try to use this:
$node = node_load(1);
$searhed_nid = '2';
$field_page_collection1 = field_get_items('node', $node, 'field_page_collection1');
foreach ($field_page_collection1 as $item) {
$field_collection = entity_load_single('field_collection_item', $item['value']);
$fc_item_wrapper = entity_metadata_wrapper('field_collection_item', $field_collection);
// lets take name the field with ref field_ref_nid.
$field_val = $fc_item_wrapper->field_ref_nid->raw();
if ($field_val == $searhed_nid) {
$field_collection->delete();
}
}

Magento gather attributes as multidimensional array keys

I need to gather all of the available attributes for the given product and then create a multidimensional array with them. Hopefully you can create a multidimensional array with more than two dimensions? The resulting array declarations should look like this:
$simpleArray[$child->getVendor()][$child->getColor()]=$child->getPrice();
First I'm gathering all the attributes then adding them to a string where I can call each one later:
$_product = $this->getProduct();
$_attributes = Mage::helper('core')->decorateArray($this->getAllowAttributes());
//Gather all attribute labels for given product
foreach($_attributes as $_attribute){
$attributeString .= '[$child -> get' . ucfirst($_attribute->getLabel()) . '()]';
}
Then I'm attempting to append that string to the array to declare it:
foreach($childProducts as $child) { //cycle through simple products to find applicable
//CAITLIN you are going to need way to search for other attributes, GET list of attributes
$simpleArray. $attributeString =$child->getPrice();
}
Mage::log('The attributeString is '. $simpleArray. $attributeString, null, 'caitlin.log'); //This is logging as "The attributeString is Array74"
Any suggestions?
You'll need to use recursion to do what you're requesting without knowing the attribute names while writing the code.
This will loop through and provide all of the child product prices, in a multi dimensional array based on the configurable attributes. It assumes that $_product is the current product.
$attrs = $_product->getTypeInstance(true)->getConfigurableAttributesAsArray($_product);
$map = array();
foreach($attrs as $attr) {
$map[] = $attr['attribute_code'];
}
$childPricing = array();
$childProducts = $_product->getTypeInstance()->getUsedProducts();
foreach($childProducts as $_child) {
// not all of the child's attributes are accessible, unless we properly load the full product
$_child = Mage::getModel('catalog/product')->load($_child->getId());
$topLevel = array($child->getData($map[sizeof($map)]) => $_child->getPrice());
array_pop($map);
$childProducts = array_merge($childProducts,$this->workThroughAttrMap($map,$_child,$topLevel));
}
//print_r childProducts to test, later do whatever you were originally planning with it.
In the same controller include this:
protected function workThroughAttrMap(&$map,$child,$topLevel) {
$topLevel = array($child->getData($map[sizeof($map)]) => $topLevel);
array_pop($map);
if(sizeof($map) > 0) return workThroughAttrMap($map,$child,$topLevel);
else return $topLevel;
}
I haven't tested this code so there may be a few minor bugs.
There are a few things you could do to make the code a bit cleaner, such as moving the first $topLevel code into the function, making that an optional parameter and initializing it with the price when it doesn't exist. I also haven't included any error checking (if the product isn't configurable, the child product doesn't have its price set, etc).

Magento - Changing attribute sorting

I'm trying to change the sorting of my products.
I want to use the attribute sort by options not to sort by name but rather sort by position given in the "manage attributes". But only when there's a position (when all is 0 it should sort by name).
For this I need to know in which file the sorting is applied to the product collection. I searched inside app\code\core\Mage\Catalog\Model\Config.php and app\code\core\Mage\Catalog\Block\Product\List.php but neither found anything about the sorting. And maybe some code suggestions, too.
Google isn't helping me with this issue, too so I try it here. Maybe somone can help me with this.
Thanks
EDIT:
As example we take the "Color" attribute, it's a drop-down attribute.
The table inside "manage attributes" looks like this:
Valuename | Position
========================
light blue | 1
blue | 2
dark blue | 3
light red | 4
red | 5
dark red | 6
In the frontend I sort by the attribute "Color" and my products will be listed this way:
blue
dark blue
dark red
light blue
light red
red
But I want it to be listed like this:
light blue
blue
dark blue
light red
red
dark red
EDIT2:
public function getAllOptions($withEmpty = true, $defaultValues = false)
{
$storeId = $this->getAttribute()->getStoreId();
if (!is_array($this->_options)) {
$this->_options = array();
}
if (!is_array($this->_optionsDefault)) {
$this->_optionsDefault = array();
}
if (!isset($this->_options[$storeId])) {
$collection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setPositionOrder('asc')
->setAttributeFilter($this->getAttribute()->getId())
->setStoreFilter($this->getAttribute()->getStoreId())
->load();
$this->_options[$storeId] = $collection->toOptionArray();
$this->_optionsDefault[$storeId] = $collection->toOptionArray('default_value');
}
$options = ($defaultValues ? $this->_optionsDefault[$storeId] : $this->_options[$storeId]);
if ($withEmpty) {
array_unshift($options, array('label' => '', 'value' => ''));
}
return $options;
}
This is almost impossible to achieve if you want to go with the actual color attribute.
The product collection can get the text value of each color from the EAV structure and run a sorting based on it. But the attribute option table isn't joined to the collection, so there's no way it could know what position you've set for your options.
I would make an workaround for that, maybe not the best overall solution, but you'll get what you want.
Create an attribute with code smth like sorting_color and label Color, and numerical options (e.g. 1,2,3). And assign proper values to each product (so "light blue" would be 1, "blue" is 2 - and so on). Then remove the actual color attribute from sorting, and add your newly created sorting_color.
As I said not the exact solution, but you could get yourself into troubles if you choose to mess up with the product collection sorting.
I was also facing the same problem and solved it by using some custom code:
I want to share here so that someone will get idea from this:
First I got all attributes options of color sorted by their position
$attribute = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'color');
if ($attribute->usesSource())
{
$options = $attribute->getSource()->getAllOptions('positions');
}
foreach($options as $val)
{
$color_attr_array[] = $val['label'];
}
I obtained all the attribute options of color sorted by their position
foreach($childProducts as $_childProduct)
{
//get the attribute option of a particular product and find itd key from the attributes array
$color_attr_val = $_childProduct->getAttributeText('color');
$color_pos = array_search($color_attr_val,$color_attr_array);
//make a new array with key indexes of attribute options
$_childproduct_final_arr[$color_pos] = $_childProduct;
}
ksort($_childproduct_final_arr);
//This is the final array of products sorted by attribute options position
I found the function addValueSortToCollection in Mage_Eav_Model_Entity_Attribute_Source_Table is what defines the sort order. By adding a LEFT JOIN to the table eav_attribute_option and pulling in the sort_order field I was able to sort by the adminhtml position of the attribute. I haven't tested fully but it seems to do what I want.
I created a separate module to rewrite this class, the only modification is to addValueSortToCollection, below this line:
Mage::getResourceModel('eav/entity_attribute_option')
->addOptionValueToCollection($collection, $this->getAttribute(), $valueExpr);
I added the following Join, and modified the getSelect statement to sort by position 1st, then alphabetical second:
// add join here to pull in sort_order for attribute
$collection->getSelect()->joinLeft(
array($this->getAttribute()->getAttributeCode() . '_option' => 'eav_attribute_option'), "{$this->getAttribute()->getAttributeCode()}_option_value_t1.option_id=" . $this->getAttribute()->getAttributeCode() . "_option.option_id"
);
$collection->getSelect()
->order("sort_order {$dir}") // Add sort_order to the select statement
->order("{$this->getAttribute()->getAttributeCode()} {$dir}");
return $this;
}
Hope someone finds this helpful.
de
Just open this file Mage/Eav/Model/Entity/Attribute/Source/table.php and there is one function is there getAllOptions() in which try this
$collection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setPositionOrder('asc')
->setAttributeFilter($this->getAttribute()->getId())
->setStoreFilter($this->getAttribute()->getStoreId())
->load();
OR
please try to see weather there is comment or not this in app/code/core/Mage/Catalog/Model/Config.php:
public function getAttributeUsedForSortByArray()
{
$options = array(
**‘position’ => Mage::helper(‘catalog’)->__(‘Position’)**
);
foreach ($this->getAttributesUsedForSortBy() as $attribute) {
/* #var $attribute Mage_Eav_Model_Entity_Attribute_Abstract */
$options[$attribute->getAttributeCode()] = $attribute->getStoreLabel();
}
return $options;
}
may this will help you
let me know if you still facing any problem

Change Manage Customer's Grid

I have created a custom module which displays a tab and a section in admin configuration panel to manage customer attributes.
I have loaded all customer attributes with a check box each.
This is my code for displaying all customer attributes as checkboxes. I want the checkbox value selected from here to be added as a column in Manage Customer Grid.
Model/Attributes.php
$attributes = Mage::getModel('customer/entity_address_attribute_collection');
$result = array();
foreach ($attributes as $attribute)
{
if (($label = $attribute->getFrontendLabel()))
$result[$attribute->getId()] = $label;
}
$attributes1 = Mage::getModel('customer/entity_attribute_collection');
$result1 = array();
foreach ($attributes1 as $attribute1)
{
if (($label1 = $attribute1->getFrontendLabel()))
$result1[$attribute1->getId()] = $label1;
}
$final = array_merge($result, $result1);
return $final;
Now based on selection of these check boxes, I would like to add an extra column in 'Manage Customer' Grid.
I tried retrieving the value of selected checkbox but I just get the array index number.
Mage::getStoreConfig('sectionname/groupname/fieldname');
Can some one tell me how to fetch the the selected checkbox value and add a column based on the selection represented by that checkbox?
Thanks in advance.
When you use array_merge you are destroying the correct indexes, which are supposed to be the attribute IDs. Also it's good practice to give your variables meaningful names.
$result = array();
$addressAttributes = Mage::getModel('customer/entity_address_attribute_collection');
foreach ($addressAttributes as $addressAttribute)
{
if (($addrlabel = $addressAttribute->getFrontendLabel()))
$result[$addressAttribute->getId()] = $addrlabel;
}
$customerAttributes = Mage::getModel('customer/entity_attribute_collection');
foreach ($customerAttributes as $customerAttribute)
{
if (($custlabel = $customerAttribute->getFrontendLabel()))
$result[$customerAttribute->getId()] = $custlabel;
}
return $result;
I suppose the next step is to remove the columns that your grid's parent will add, these are stored in a grid's protected _columns property. Not all columns are to be removed, such as the massaction column. Then add your chosen columns back in.
protected function _prepareColumns()
{
parent::_prepareColumns();
// remove the excess columns here
$attributeIds = Mage::getStoreConfig('sectionname/groupname/fieldname');
$attributes = Mage::getModel('eav/entity_attribute')->getCollection()
->addFieldToFilter('attribute_id', array('in' => $attributeIds));
foreach ($attributes as $attribute)
{
$options = array();
if ($attribute->getFrontendInput() == 'select') {
foreach ($attribute->getSource()->getAllOptions() as $value) {
$options[$value['value']] = $value['label'];
}
}
$this->addColumn($attribute->getCode(), array(
'index' => $attribute->getCode(),
'header' => $attribute->getFrontendLabel(),
'type' => $attribute->getFrontendInput(),
'options' => $options
));
}
return $this;
}
This way may lose useful formatting like column widths, etc. so a more sophisticated way would be to work out which columns are already in place and leave them, then only remove those that haven't been selected.
I would, in your module, set in config.xml that you are overwrting the Block Mage_Adminhtml_Block_Customer_Grid with your own block (which inherits from Mage_Adminhtml_Block_Customer_Grid) and in your own block make a function
protected function _prepareColumns()
{
$this->addColumn('mycolumn', array(
'header' => Mage::helper('customer')->__('My Column'),
'index' => 'key',
));
return parent::_prepareColumns();
}
Without knowing more about your data its hard to give better advice, but this should be enough to get you started.

Categories