SlideShare una empresa de Scribd logo
1 de 69
Descargar para leer sin conexión
Magento attributes
Fresh view

Monday, October 14, 13
Alex Gotgelf
Senior Software Developer at Eltrino
Contacts:
alex@eltrino.com
ramzes3988
http://www.linkedin.com/in/gotgelf

Monday, October 14, 13
Lecture Overview

‣ Magento Attributes EAV concepts
‣ Not trivial problems and solutions

Monday, October 14, 13
EAV History
EAV has quite a long history. Some of its earliest applications
were storage systems for clinical data back in 1970s.
As a storage method EAV borrows from early object-oriented
languages. SIMULA 67 is cited as one such influence. Functional
languages such as LISP are also known to have contributed to the
development of EAV. They contain storage structures that record
object information in attribute-value pairs – a principle
fundamental to EAV.

Monday, October 14, 13
EAV conception
‣ E - Entity
‣ A - Attribute
‣ V - Value

Monday, October 14, 13
EAV conception
Eav becomes especially useful when the
following conditions are presented:

‣ Entity attributes vary significantly in terms of
data type

‣ The number of possible entity types is large
and entity types have individual sets of
attributes

Monday, October 14, 13
Advantages of EAV
‣ Scalability - you can change your data
without changing the structure of db

‣ Flexible mechanism to work with attributes
associated to entity

Monday, October 14, 13
Weakness of EAV

‣ Performance (complex join structures etc...)

Monday, October 14, 13
Attributes Bottlenecks
in Magento

Monday, October 14, 13
Problem #1

Problem #1
Product Select Attribute with Large Options Set
(several thousands of options) at the admin side

Monday, October 14, 13
Problem #1

Let’s create select attribute with 5 options
PHP

$installer = $this;
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select',
array(
'group'
=> 'General',
'type'
=> 'int',
'input'
=> 'select',
'label'
=> 'Test Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
));
$attributeId = $installer
->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'test_select');
for ($i = 1; $i <= 5; $i++) {
$data[] = 'Opt' . $i;
}
$option = array (
'attribute_id' => $attributeId,
'values' => $data
);
$this->addAttributeOption($option);
$installer->endSetup();

Monday, October 14, 13
Problem #1

•
•

Monday, October 14, 13

Usability
Performance
Problem #1

Let’s create select attribute with 10000 options
PHP

$installer = $this;
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select',
array(
'group'
=> 'General',
'type'
=> 'int',
'input'
=> 'select',
'label'
=> 'Test Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
));
$attributeId = $installer
->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'test_select');
for ($i = 1; $i <= 10000; $i++) {
$data[] = 'Opt' . $i;
}
$option = array (
'attribute_id' => $attributeId,
'values' => $data
);
$this->addAttributeOption($option);
$installer->endSetup();

Monday, October 14, 13
Problem #1

Problem #1

•
•

Monday, October 14, 13

Usability
Performance
Problem #1

Let’s create select attribute with 35000 options
PHP

$installer = $this;
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select',
array(
'group'
=> 'General',
'type'
=> 'int',
'input'
=> 'select',
'label'
=> 'Test Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
));
$attributeId = $installer
->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'test_select');
for ($i = 1; $i <= 35000; $i++) {
$data[] = 'Opt' . $i;
}
$option = array (
'attribute_id' => $attributeId,
'values' => $data
);
$this->addAttributeOption($option);
$installer->endSetup();

Monday, October 14, 13
Problem #1

Problem #1
memory_limit:
1024M

•
•

Usability
Performance

Monday, October 14, 13

Fatal error : Allowed memory size of
268435456 bytes exhausted (tried to
allocate 32 bytes
Problem #1

As Result

Monday, October 14, 13
Problem #1

Solution for Problem #1- AutoComplete

Monday, October 14, 13
Problem #1

Problem #1 - Solution
y based
2 - jquer
Select
ent for
e placem
r
Select Boxes

Monday, October 14, 13
Problem #1

Problem #1 - Solution

http://ivaynberg.github.io/select2/

Monday, October 14, 13
Problem #1

Select2 Advantages

‣
‣

Enhancing native selects with search

‣

Nesting opt-groups: native selects only support one level of
nested. Select2 does not have this restriction.

‣
‣

Tagging: ability to add new items on the fly.

‣

etc ...

Loading data from JavaScript: easily load items via ajax and have
them searchable.

Working with large, remote datasets: ability to partially load a
dataset based on the search term.

Monday, October 14, 13
Problem #1

Magento Renderers
Varien_Data_Form_Element

‣
‣
‣
‣
‣
‣
Monday, October 14, 13

Button
Checkbox
Select
Text
Radio
...
Problem #1

Step 1 - create test attribute with custom renderer
PHP

<?php
$installer = $this;
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select',
array(
'group'
=> 'General',
'type'
=> 'int',
'input'
=> 'select2',
'label'
=> 'Test Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
'input_renderer'
=> 'examples_customselect/renderer_select'
));

custom renderer

Monday, October 14, 13
Problem #1

Step 2 - create layout with select2 js and css files
XML

<reference name="head">
<action method="addItem"><type>js_css</type>
<name>jquery/select2/select2.css</name><params/>
</action>
<action method="addJs">
<file>jquery/jquery-1.9.min.js</file>
<params><![CDATA[name="js_001_first"]]></params>
</action>
<action method="addJs">
<file>jquery/select2/select2.min.js</file>
<params><![CDATA[name="js_002_second"]]></params>
</action>
</reference>

Monday, October 14, 13
Problem #1

Step 3 - create custom renderer block
PHP

public function getElementHtml()
{
$html = '
<p>
<input type="hidden"
id = "test_attribute"
name = "product[test_attribute]"
value = ' . $this->getValue() . '
data-placeholder="-- Please select --"
style="width:300px"/>
</p>';
$defaultOptionText = $this->getDefaultOptionText();
...

Monday, October 14, 13
Problem #1

Step 3 - create custom renderer block
PHP

...
$js = <<<EOF
<script type="text/javascript">
jQuery.noConflict()(document).ready(function() {
jQuery.noConflict()('#test_attribute').select2({
minimumInputLength: 4,
placeholder: 'Search',
ajax: {
url: '{$this->getLink()}',
dataType: 'json',
data: function(term, page) {
return {
search: term,
attribute_code: '{$this->getId()}'
};
},
results: function (data, page) {
return { results: data };
}
},
...
Monday, October 14, 13
Problem #1

Step 3 - create custom renderer block
PHP

...
initSelection : function (element, callback) {
var data = {id: '{$this->getValue()}', text:
'{$defaultOptionText}'};
callback(data);
}
});
});
</script>
EOF;
$html .= $js;
return $html;
}

Monday, October 14, 13
Problem #1

Step 4 - create admin controller
PHP

public function testAction()
{
if (!$this->getRequest()->isAjax()) {
$this->_forward('noRoute');
return;
}
$search = $this->getRequest()->getParam('search');
$attributeCode = $this->getRequest()->getParam('attribute_code');
$attribute = Mage::getModel('eav/entity_attribute')->
loadByCode(Mage_Catalog_Model_Product::ENTITY, $attributeCode);
$options = Mage::getModel('examples_customselect/select')->
getAttributesLikeSearch($attribute->getId(), $search);
$this->getResponse()->setBody(Mage::helper('core')->
jsonEncode($options));
}

Monday, October 14, 13
Problem #1

Step 5 - create model and resource model
PHP

loading array data using ajax
...
$select = $this->_getReadAdapter()->select()->from(array('a' => $this>getTable('eav/attribute_option_value')))
->joinLeft(
array('b' => $this->getTable('eav/attribute_option')),
'a.option_id = b.option_id',
array()
)
->where('a.store_id = ?', $store->getId())
->where('b.attribute_id = ?', $attributeId)
->where('a.value LIKE ?', $search .'%');
...

Monday, October 14, 13
Problem #1

Problem #1 - Solution
https://github.com/gotgelf/
magento-examples

Customselect Module

Monday, October 14, 13
Problem #2

Problem #2
Saving Attribute via admin side with a Large
Number of Options

Monday, October 14, 13
Problem #2

Monday, October 14, 13
Problem #2

...

Monday, October 14, 13
Problem #2

Problem #2
• Change Opt1, change Opt300
• Click “Save Attribute” button
• As result Opt1 will be changed and Opt300
will not

Monday, October 14, 13
Problem #2

Problem #2
Problem: POST request is truncated, so
we need to increase it’s size
Solution: increase max_input_vars (since
PHP 5.3.9 ) variable, by default it’s 1000

Monday, October 14, 13
Problem #3

Problem #3
Product Select Attribute with Large Options Set
(several thousands of options) at the Frontend

Monday, October 14, 13
Problem #3

Let’s create select attribute with 10000 options
$installer = $this;
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY,
'frontend_select', array(
'group'
=> 'General',
'type'
=> 'varchar',
'input'
=> 'int',
'label'
=> 'Frontend Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
'visible_on_front'
=> true,
));

} important !

$attributeId = $installer
->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'frontend_select');
for ($i = 1; $i <= 10000; $i++) {
$data[] = 'Opt' . $i;
}
$option = array (
'attribute_id' => $attributeId,
'values' => $data
);
$this->addAttributeOption($option);
$installer->endSetup();

Monday, October 14, 13
Problem #3

Problem #3
•

Crete test product and
assign to it some option

•

Go to Frontend

Monday, October 14, 13
Problem #3

Problem #3

Option load
takes about
0.9 sec !!!

Monday, October 14, 13
Problem #3

Problem #3
Mage_Catalog_Block_Product_
View_Attribtues

Mage_Eav_ModelEntity_Attribute
_Frontend_Abstract

Mage_Eav_ModelEntity_Attribute
_Source_Table

getAdditionalData()
getValue()

getOption()

getOptionText()
getAllOptions()

Monday, October 14, 13
Problem #3

We load all options to retrieve selected option text !!!
PHP

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;
}
Monday, October 14, 13
Problem #3

Problem #3 - Solution
ttribute Custom
A
ontend Model
Fr

Monday, October 14, 13
Problem #3

Step 1 - create test attribute with custom frontend model
PHP

...
$installer = $this;
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY,
'frontend_select', array(
'group'
=> 'General',
'type'
=> 'varchar',
'input'
=> 'int',
'label'
=> 'Frontend Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
'frontend'
=>
'examples_customselect/catalog_product_attribute_frontend_select',
'visible_on_front'
=> true,
));
...

Сustom Frontend Model

Monday, October 14, 13
Problem #3

Problem #3
Mage_Catalog_Block_Product_
View_Attribtues

Examples_Сustomselect_Model_Catalog_Pro
duct_Attribute_Frontend_Select

getAdditionalData()
getValue()

Monday, October 14, 13
Problem #3

Step 2 - create getValue() method at our custom model
PHP

public function getValue(Varien_Object $object)
{
$optionId = $object->getData($this->getAttribute()
->getAttributeCode());
$storeId = $this->getAttribute()->getStoreId();
$data = Mage::getModel('examples_customselect/select')
->getOptionText($optionId, $storeId);
$value = $data['value'];
return $value;
}

Monday, October 14, 13
Problem #3

Problem #3

Option load
takes about
0.0014 sec !!!
instead 0.9

Monday, October 14, 13
Problem #4

Problem #4
Layer Navigation Issues
(a lot of attributes or a lot of options)

Monday, October 14, 13
Problem #4

Problem #4
For each attribute which is used for Layer Navigation, it will
make a call to getAllOptions() method at
Mage_Eav_Model_Entity_Attribute_Source_Table model
and during this call we will load all attribute option
collection !!!

Monday, October 14, 13
Problem #4

Problem #4
PHP

public function getAllOptions($withEmpty = true, $defaultValues = false)
{
...
$collection = Mage::getResourceModel('eav/
entity_attribute_option_collection')
->setPositionOrder('asc')
->setAttributeFilter($this->getAttribute()->getId())
->setStoreFilter($this->getAttribute()->getStoreId())
->load();
...
}

Monday, October 14, 13
Problem #4

Problem #4 - Solution
n s m e t h od
e t Al l O p t i o
e custom g
reat
es for all
C
ad all valu
hich will lo
w
s at once
attribute
variable)
sing static
(u

Monday, October 14, 13
Problem #4

Problem #4 - Solution
PHP

public function getAllOptions($withEmpty = true, $defaultValues = false)
{
...
if (!isset($this->_options[$storeId])) {
$options = $this->_getAttributeOptionsByStore($storeId,
$this->getAttribute()->getId());
$this->_options[$storeId]
= $options['store'];
$this->_optionsDefault[$storeId] = $options['default'];
}
...
}

Monday, October 14, 13
Problem #4

Problem #4 - Solution
PHP

protected static $_predefinedOptions = array();
protected static function _getAttributeOptionsByStore($storeId, $attributeId)
{
if (!isset(self::$_predefinedOptions[$storeId])) {
// load options collection
}
if (isset(self::$_predefinedOptions[$storeId][$attributeId])) {
return self:: $_predefinedOptions[$storeId][$attributeId];
}
}

Monday, October 14, 13
Problem #4

Problem #4
Preconditions: one dropdown attribute
with 10000 options, used at layer
navigation. Cache is disabled.

Monday, October 14, 13
Problem #4

Category Page, loading time

Monday, October 14, 13
Problem #5

Problem #5
Usage of attribute created via install script at Layer
Navigation

Monday, October 14, 13
Problem #5

Problem #5
PHP

...
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select',
array(
'group'
=> 'General',
'type'
=> 'int',

// int or varchar type ?
'input'
=> 'select',
'label'
=> 'Test Select',
'global'
=>
Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'required'
=> true,
));
...

Monday, October 14, 13
Problem #5

if backend_type is varchar, our attribute will not work
correctly at Layer Navigation (as example - default Magento
attribute ‘manufacture’), use int backend type instead.
PHP

protected function _getIndexableAttributes($multiSelect)
{
$select = ...
if ($multiSelect == true) {
$select->where('ea.backend_type = ?', 'varchar')
->where('ea.frontend_input = ?', 'multiselect');
} else {
$select->where('ea.backend_type = ?', 'int')
->where('ea.frontend_input = ?', 'select');
}
return $this->_getReadAdapter()->fetchCol($select);
}

Monday, October 14, 13
Problem #6

Problem #6
Load all category collection
(getStoreCategories() method) to add
needed attributes for each item in the
collection.

Monday, October 14, 13
Problem #6

Mage_Catalog_Model_Resource_Category_Tree
PHP

protected function _getDefaultCollection($sorted = false)
{
$this->_joinUrlRewriteIntoCollection = true;
$collection = Mage::getModel('catalog/category')->getCollection();
$attributes = Mage::getConfig()->getNode('frontend/category/
collection/attributes');
if ($attributes) {
$attributes = $attributes->asArray();
$attributes = array_keys($attributes);
}
$collection->addAttributeToSelect($attributes);
...
}

Monday, October 14, 13
Problem #6

Catalog/etc/config.xml
XML

<category>
<collection>
<attributes>
<name/>
<url_key/>
<is_active/>
</attributes>
</collection>
</category>

Monday, October 14, 13
Additional Example
Change Product Attribute Set (for simple
products) on the Fly

Monday, October 14, 13
Monday, October 14, 13
Step 1 - add Observer to create new mass action
PHP

public function addNewActionToProductGrid($observer)
{
$block = $observer->getBlock();
if ($block instanceof Mage_Adminhtml_Block_Catalog_Product_Grid){
$attributeSets = Mage::getResourceModel('eav/
entity_attribute_set_collection')
->setEntityTypeFilter(Mage::getModel('catalog/product')>getResource()->getTypeId())
->load()
->toOptionHash();
...

Monday, October 14, 13
Step 1 - add Observer to create new mass action
PHP

$block->getMassactionBlock()->addItem('attr_set', array(
'label'=> Mage::helper('catalog')->__('Change Attribute
Set'),
'url' => $block->getUrl('*/index/test',
array('_current'=>true)),
'additional' => array(
'visibility' => array(
'name'
=> 'attribute_set',
'type'
=> 'select',
'class' => 'required-entry',
'label' => Mage::helper('catalog')->__('Select
Attribute Set'),
'values' => $attributeSets
)
)
));
}
}

Monday, October 14, 13
Step 2 - create custom Controller
PHP

...
foreach ($productIds as $productId) {
$product = Mage::getSingleton('catalog/product')->load($productId);
$attributes = Mage::getModel('catalog/
product_attribute_api')->items($product->getAttributeSetId());
$product
->setStoreId($storeId)
->setAttributeSetId($this->getRequest()->getParam('attribute_set'))
->setIsMassupdate(true)
->save();
$this->_cleanOldAttributeValues($product, $attributes);
}
...

Monday, October 14, 13
Step 3 - remove old attribute’s values
PHP

protected function _cleanOldAttributeValues($product, $attributes)
{
$productResource = $product->getResource();
foreach ($attributes as $attribute) {
if (!in_array($attribute['code'], $this->_fixAttributes)) {
$product->setData($attribute['code'], null);
$productResource->saveAttribute($product, $attribute['code']);
}
}
return $this;
}

Monday, October 14, 13
There are two ways of constructing a
software design: One way is to make it so
simple that there are obviously no
deficiencies, and the other way is to make it
so complicated that there are no obvious
deficiencies. The first method is far more
difficult.
(Tony Hoare)

Monday, October 14, 13
https://twitter.com/gotgelf

Monday, October 14, 13
ou !
nk Y
Th a
ions
uest
Q

Monday, October 14, 13

Más contenido relacionado

La actualidad más candente

Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
Fabien Potencier
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
Fabien Potencier
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
Fabien Potencier
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOP
Wildan Maulana
 

La actualidad más candente (20)

Test driven development_for_php
Test driven development_for_phpTest driven development_for_php
Test driven development_for_php
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHPKonf
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patterns
 
Your code sucks, let's fix it - PHP Master Series 2012
Your code sucks, let's fix it - PHP Master Series 2012Your code sucks, let's fix it - PHP Master Series 2012
Your code sucks, let's fix it - PHP Master Series 2012
 
jQuery Plugin
jQuery PluginjQuery Plugin
jQuery Plugin
 
Your code sucks, let's fix it
Your code sucks, let's fix itYour code sucks, let's fix it
Your code sucks, let's fix it
 
Your code sucks, let's fix it (CakeFest2012)
Your code sucks, let's fix it (CakeFest2012)Your code sucks, let's fix it (CakeFest2012)
Your code sucks, let's fix it (CakeFest2012)
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
 
Sylius and Api Platform The story of integration
Sylius and Api Platform The story of integrationSylius and Api Platform The story of integration
Sylius and Api Platform The story of integration
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOP
 
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
Сергей Иващенко - Meet Magento Ukraine - Цены в Magento 2
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more Reactive
 
Drupal 8: Routing & More
Drupal 8: Routing & MoreDrupal 8: Routing & More
Drupal 8: Routing & More
 
PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examples
 

Similar a Magento Attributes - Fresh View

Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)
Ivan Chepurnyi
 
Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)
Pavel Novitsky
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8
PrinceGuru MS
 
Parsing in ios to create an app
Parsing in ios to create an appParsing in ios to create an app
Parsing in ios to create an app
HeaderLabs .
 

Similar a Magento Attributes - Fresh View (20)

Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)Making Magento flying like a rocket! (A set of valuable tips for developers)
Making Magento flying like a rocket! (A set of valuable tips for developers)
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching logging
 
What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...What is this DI and AOP stuff anyway...
What is this DI and AOP stuff anyway...
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Advanced PHPUnit Testing
Advanced PHPUnit TestingAdvanced PHPUnit Testing
Advanced PHPUnit Testing
 
Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)Meet Magento Belarus debug Pavel Novitsky (eng)
Meet Magento Belarus debug Pavel Novitsky (eng)
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Using of TDD practices for Magento
Using of TDD practices for MagentoUsing of TDD practices for Magento
Using of TDD practices for Magento
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Utilization of zend an ultimate alternate for intense data processing
Utilization of zend  an ultimate alternate for intense data processingUtilization of zend  an ultimate alternate for intense data processing
Utilization of zend an ultimate alternate for intense data processing
 
Teaching Programming Online
Teaching Programming OnlineTeaching Programming Online
Teaching Programming Online
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
Core Php Component Presentation
Core Php Component PresentationCore Php Component Presentation
Core Php Component Presentation
 
Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8Corephpcomponentpresentation 1211425966721657-8
Corephpcomponentpresentation 1211425966721657-8
 
How to write not breakable unit tests
How to write not breakable unit testsHow to write not breakable unit tests
How to write not breakable unit tests
 
Parsing in ios to create an app
Parsing in ios to create an appParsing in ios to create an app
Parsing in ios to create an app
 
Growing up with Magento
Growing up with MagentoGrowing up with Magento
Growing up with Magento
 
Magento Indexes
Magento IndexesMagento Indexes
Magento Indexes
 
Lithium Best
Lithium Best Lithium Best
Lithium Best
 
Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010
 

Último

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Último (20)

Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 

Magento Attributes - Fresh View

  • 2. Alex Gotgelf Senior Software Developer at Eltrino Contacts: alex@eltrino.com ramzes3988 http://www.linkedin.com/in/gotgelf Monday, October 14, 13
  • 3. Lecture Overview ‣ Magento Attributes EAV concepts ‣ Not trivial problems and solutions Monday, October 14, 13
  • 4. EAV History EAV has quite a long history. Some of its earliest applications were storage systems for clinical data back in 1970s. As a storage method EAV borrows from early object-oriented languages. SIMULA 67 is cited as one such influence. Functional languages such as LISP are also known to have contributed to the development of EAV. They contain storage structures that record object information in attribute-value pairs – a principle fundamental to EAV. Monday, October 14, 13
  • 5. EAV conception ‣ E - Entity ‣ A - Attribute ‣ V - Value Monday, October 14, 13
  • 6. EAV conception Eav becomes especially useful when the following conditions are presented: ‣ Entity attributes vary significantly in terms of data type ‣ The number of possible entity types is large and entity types have individual sets of attributes Monday, October 14, 13
  • 7. Advantages of EAV ‣ Scalability - you can change your data without changing the structure of db ‣ Flexible mechanism to work with attributes associated to entity Monday, October 14, 13
  • 8. Weakness of EAV ‣ Performance (complex join structures etc...) Monday, October 14, 13
  • 10. Problem #1 Problem #1 Product Select Attribute with Large Options Set (several thousands of options) at the admin side Monday, October 14, 13
  • 11. Problem #1 Let’s create select attribute with 5 options PHP $installer = $this; $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select', array( 'group' => 'General', 'type' => 'int', 'input' => 'select', 'label' => 'Test Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, )); $attributeId = $installer ->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'test_select'); for ($i = 1; $i <= 5; $i++) { $data[] = 'Opt' . $i; } $option = array ( 'attribute_id' => $attributeId, 'values' => $data ); $this->addAttributeOption($option); $installer->endSetup(); Monday, October 14, 13
  • 12. Problem #1 • • Monday, October 14, 13 Usability Performance
  • 13. Problem #1 Let’s create select attribute with 10000 options PHP $installer = $this; $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select', array( 'group' => 'General', 'type' => 'int', 'input' => 'select', 'label' => 'Test Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, )); $attributeId = $installer ->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'test_select'); for ($i = 1; $i <= 10000; $i++) { $data[] = 'Opt' . $i; } $option = array ( 'attribute_id' => $attributeId, 'values' => $data ); $this->addAttributeOption($option); $installer->endSetup(); Monday, October 14, 13
  • 14. Problem #1 Problem #1 • • Monday, October 14, 13 Usability Performance
  • 15. Problem #1 Let’s create select attribute with 35000 options PHP $installer = $this; $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select', array( 'group' => 'General', 'type' => 'int', 'input' => 'select', 'label' => 'Test Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, )); $attributeId = $installer ->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'test_select'); for ($i = 1; $i <= 35000; $i++) { $data[] = 'Opt' . $i; } $option = array ( 'attribute_id' => $attributeId, 'values' => $data ); $this->addAttributeOption($option); $installer->endSetup(); Monday, October 14, 13
  • 16. Problem #1 Problem #1 memory_limit: 1024M • • Usability Performance Monday, October 14, 13 Fatal error : Allowed memory size of 268435456 bytes exhausted (tried to allocate 32 bytes
  • 18. Problem #1 Solution for Problem #1- AutoComplete Monday, October 14, 13
  • 19. Problem #1 Problem #1 - Solution y based 2 - jquer Select ent for e placem r Select Boxes Monday, October 14, 13
  • 20. Problem #1 Problem #1 - Solution http://ivaynberg.github.io/select2/ Monday, October 14, 13
  • 21. Problem #1 Select2 Advantages ‣ ‣ Enhancing native selects with search ‣ Nesting opt-groups: native selects only support one level of nested. Select2 does not have this restriction. ‣ ‣ Tagging: ability to add new items on the fly. ‣ etc ... Loading data from JavaScript: easily load items via ajax and have them searchable. Working with large, remote datasets: ability to partially load a dataset based on the search term. Monday, October 14, 13
  • 23. Problem #1 Step 1 - create test attribute with custom renderer PHP <?php $installer = $this; $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select', array( 'group' => 'General', 'type' => 'int', 'input' => 'select2', 'label' => 'Test Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, 'input_renderer' => 'examples_customselect/renderer_select' )); custom renderer Monday, October 14, 13
  • 24. Problem #1 Step 2 - create layout with select2 js and css files XML <reference name="head"> <action method="addItem"><type>js_css</type> <name>jquery/select2/select2.css</name><params/> </action> <action method="addJs"> <file>jquery/jquery-1.9.min.js</file> <params><![CDATA[name="js_001_first"]]></params> </action> <action method="addJs"> <file>jquery/select2/select2.min.js</file> <params><![CDATA[name="js_002_second"]]></params> </action> </reference> Monday, October 14, 13
  • 25. Problem #1 Step 3 - create custom renderer block PHP public function getElementHtml() { $html = ' <p> <input type="hidden" id = "test_attribute" name = "product[test_attribute]" value = ' . $this->getValue() . ' data-placeholder="-- Please select --" style="width:300px"/> </p>'; $defaultOptionText = $this->getDefaultOptionText(); ... Monday, October 14, 13
  • 26. Problem #1 Step 3 - create custom renderer block PHP ... $js = <<<EOF <script type="text/javascript"> jQuery.noConflict()(document).ready(function() { jQuery.noConflict()('#test_attribute').select2({ minimumInputLength: 4, placeholder: 'Search', ajax: { url: '{$this->getLink()}', dataType: 'json', data: function(term, page) { return { search: term, attribute_code: '{$this->getId()}' }; }, results: function (data, page) { return { results: data }; } }, ... Monday, October 14, 13
  • 27. Problem #1 Step 3 - create custom renderer block PHP ... initSelection : function (element, callback) { var data = {id: '{$this->getValue()}', text: '{$defaultOptionText}'}; callback(data); } }); }); </script> EOF; $html .= $js; return $html; } Monday, October 14, 13
  • 28. Problem #1 Step 4 - create admin controller PHP public function testAction() { if (!$this->getRequest()->isAjax()) { $this->_forward('noRoute'); return; } $search = $this->getRequest()->getParam('search'); $attributeCode = $this->getRequest()->getParam('attribute_code'); $attribute = Mage::getModel('eav/entity_attribute')-> loadByCode(Mage_Catalog_Model_Product::ENTITY, $attributeCode); $options = Mage::getModel('examples_customselect/select')-> getAttributesLikeSearch($attribute->getId(), $search); $this->getResponse()->setBody(Mage::helper('core')-> jsonEncode($options)); } Monday, October 14, 13
  • 29. Problem #1 Step 5 - create model and resource model PHP loading array data using ajax ... $select = $this->_getReadAdapter()->select()->from(array('a' => $this>getTable('eav/attribute_option_value'))) ->joinLeft( array('b' => $this->getTable('eav/attribute_option')), 'a.option_id = b.option_id', array() ) ->where('a.store_id = ?', $store->getId()) ->where('b.attribute_id = ?', $attributeId) ->where('a.value LIKE ?', $search .'%'); ... Monday, October 14, 13
  • 30. Problem #1 Problem #1 - Solution https://github.com/gotgelf/ magento-examples Customselect Module Monday, October 14, 13
  • 31. Problem #2 Problem #2 Saving Attribute via admin side with a Large Number of Options Monday, October 14, 13
  • 34. Problem #2 Problem #2 • Change Opt1, change Opt300 • Click “Save Attribute” button • As result Opt1 will be changed and Opt300 will not Monday, October 14, 13
  • 35. Problem #2 Problem #2 Problem: POST request is truncated, so we need to increase it’s size Solution: increase max_input_vars (since PHP 5.3.9 ) variable, by default it’s 1000 Monday, October 14, 13
  • 36. Problem #3 Problem #3 Product Select Attribute with Large Options Set (several thousands of options) at the Frontend Monday, October 14, 13
  • 37. Problem #3 Let’s create select attribute with 10000 options $installer = $this; $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'frontend_select', array( 'group' => 'General', 'type' => 'varchar', 'input' => 'int', 'label' => 'Frontend Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, 'visible_on_front' => true, )); } important ! $attributeId = $installer ->getAttributeId(Mage_Catalog_Model_Product::ENTITY, 'frontend_select'); for ($i = 1; $i <= 10000; $i++) { $data[] = 'Opt' . $i; } $option = array ( 'attribute_id' => $attributeId, 'values' => $data ); $this->addAttributeOption($option); $installer->endSetup(); Monday, October 14, 13
  • 38. Problem #3 Problem #3 • Crete test product and assign to it some option • Go to Frontend Monday, October 14, 13
  • 39. Problem #3 Problem #3 Option load takes about 0.9 sec !!! Monday, October 14, 13
  • 41. Problem #3 We load all options to retrieve selected option text !!! PHP 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; } Monday, October 14, 13
  • 42. Problem #3 Problem #3 - Solution ttribute Custom A ontend Model Fr Monday, October 14, 13
  • 43. Problem #3 Step 1 - create test attribute with custom frontend model PHP ... $installer = $this; $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'frontend_select', array( 'group' => 'General', 'type' => 'varchar', 'input' => 'int', 'label' => 'Frontend Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, 'frontend' => 'examples_customselect/catalog_product_attribute_frontend_select', 'visible_on_front' => true, )); ... Сustom Frontend Model Monday, October 14, 13
  • 45. Problem #3 Step 2 - create getValue() method at our custom model PHP public function getValue(Varien_Object $object) { $optionId = $object->getData($this->getAttribute() ->getAttributeCode()); $storeId = $this->getAttribute()->getStoreId(); $data = Mage::getModel('examples_customselect/select') ->getOptionText($optionId, $storeId); $value = $data['value']; return $value; } Monday, October 14, 13
  • 46. Problem #3 Problem #3 Option load takes about 0.0014 sec !!! instead 0.9 Monday, October 14, 13
  • 47. Problem #4 Problem #4 Layer Navigation Issues (a lot of attributes or a lot of options) Monday, October 14, 13
  • 48. Problem #4 Problem #4 For each attribute which is used for Layer Navigation, it will make a call to getAllOptions() method at Mage_Eav_Model_Entity_Attribute_Source_Table model and during this call we will load all attribute option collection !!! Monday, October 14, 13
  • 49. Problem #4 Problem #4 PHP public function getAllOptions($withEmpty = true, $defaultValues = false) { ... $collection = Mage::getResourceModel('eav/ entity_attribute_option_collection') ->setPositionOrder('asc') ->setAttributeFilter($this->getAttribute()->getId()) ->setStoreFilter($this->getAttribute()->getStoreId()) ->load(); ... } Monday, October 14, 13
  • 50. Problem #4 Problem #4 - Solution n s m e t h od e t Al l O p t i o e custom g reat es for all C ad all valu hich will lo w s at once attribute variable) sing static (u Monday, October 14, 13
  • 51. Problem #4 Problem #4 - Solution PHP public function getAllOptions($withEmpty = true, $defaultValues = false) { ... if (!isset($this->_options[$storeId])) { $options = $this->_getAttributeOptionsByStore($storeId, $this->getAttribute()->getId()); $this->_options[$storeId] = $options['store']; $this->_optionsDefault[$storeId] = $options['default']; } ... } Monday, October 14, 13
  • 52. Problem #4 Problem #4 - Solution PHP protected static $_predefinedOptions = array(); protected static function _getAttributeOptionsByStore($storeId, $attributeId) { if (!isset(self::$_predefinedOptions[$storeId])) { // load options collection } if (isset(self::$_predefinedOptions[$storeId][$attributeId])) { return self:: $_predefinedOptions[$storeId][$attributeId]; } } Monday, October 14, 13
  • 53. Problem #4 Problem #4 Preconditions: one dropdown attribute with 10000 options, used at layer navigation. Cache is disabled. Monday, October 14, 13
  • 54. Problem #4 Category Page, loading time Monday, October 14, 13
  • 55. Problem #5 Problem #5 Usage of attribute created via install script at Layer Navigation Monday, October 14, 13
  • 56. Problem #5 Problem #5 PHP ... $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'test_select', array( 'group' => 'General', 'type' => 'int', // int or varchar type ? 'input' => 'select', 'label' => 'Test Select', 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 'required' => true, )); ... Monday, October 14, 13
  • 57. Problem #5 if backend_type is varchar, our attribute will not work correctly at Layer Navigation (as example - default Magento attribute ‘manufacture’), use int backend type instead. PHP protected function _getIndexableAttributes($multiSelect) { $select = ... if ($multiSelect == true) { $select->where('ea.backend_type = ?', 'varchar') ->where('ea.frontend_input = ?', 'multiselect'); } else { $select->where('ea.backend_type = ?', 'int') ->where('ea.frontend_input = ?', 'select'); } return $this->_getReadAdapter()->fetchCol($select); } Monday, October 14, 13
  • 58. Problem #6 Problem #6 Load all category collection (getStoreCategories() method) to add needed attributes for each item in the collection. Monday, October 14, 13
  • 59. Problem #6 Mage_Catalog_Model_Resource_Category_Tree PHP protected function _getDefaultCollection($sorted = false) { $this->_joinUrlRewriteIntoCollection = true; $collection = Mage::getModel('catalog/category')->getCollection(); $attributes = Mage::getConfig()->getNode('frontend/category/ collection/attributes'); if ($attributes) { $attributes = $attributes->asArray(); $attributes = array_keys($attributes); } $collection->addAttributeToSelect($attributes); ... } Monday, October 14, 13
  • 61. Additional Example Change Product Attribute Set (for simple products) on the Fly Monday, October 14, 13
  • 63. Step 1 - add Observer to create new mass action PHP public function addNewActionToProductGrid($observer) { $block = $observer->getBlock(); if ($block instanceof Mage_Adminhtml_Block_Catalog_Product_Grid){ $attributeSets = Mage::getResourceModel('eav/ entity_attribute_set_collection') ->setEntityTypeFilter(Mage::getModel('catalog/product')>getResource()->getTypeId()) ->load() ->toOptionHash(); ... Monday, October 14, 13
  • 64. Step 1 - add Observer to create new mass action PHP $block->getMassactionBlock()->addItem('attr_set', array( 'label'=> Mage::helper('catalog')->__('Change Attribute Set'), 'url' => $block->getUrl('*/index/test', array('_current'=>true)), 'additional' => array( 'visibility' => array( 'name' => 'attribute_set', 'type' => 'select', 'class' => 'required-entry', 'label' => Mage::helper('catalog')->__('Select Attribute Set'), 'values' => $attributeSets ) ) )); } } Monday, October 14, 13
  • 65. Step 2 - create custom Controller PHP ... foreach ($productIds as $productId) { $product = Mage::getSingleton('catalog/product')->load($productId); $attributes = Mage::getModel('catalog/ product_attribute_api')->items($product->getAttributeSetId()); $product ->setStoreId($storeId) ->setAttributeSetId($this->getRequest()->getParam('attribute_set')) ->setIsMassupdate(true) ->save(); $this->_cleanOldAttributeValues($product, $attributes); } ... Monday, October 14, 13
  • 66. Step 3 - remove old attribute’s values PHP protected function _cleanOldAttributeValues($product, $attributes) { $productResource = $product->getResource(); foreach ($attributes as $attribute) { if (!in_array($attribute['code'], $this->_fixAttributes)) { $product->setData($attribute['code'], null); $productResource->saveAttribute($product, $attribute['code']); } } return $this; } Monday, October 14, 13
  • 67. There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult. (Tony Hoare) Monday, October 14, 13
  • 69. ou ! nk Y Th a ions uest Q Monday, October 14, 13