diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute.php
new file mode 100644
index 00000000000..4238eb3f2b4
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute.php
@@ -0,0 +1,36 @@
+_controller = 'customer_address_attribute';
+ $this->_headerText = Mage::helper('customer')->__('Manage Customer Address Attributes');
+ $this->_addButtonLabel = Mage::helper('customer')->__('Add New Attribute');
+ parent::__construct();
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit.php
new file mode 100644
index 00000000000..c0fb9589c91
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit.php
@@ -0,0 +1,92 @@
+_objectId = 'attribute_id';
+ $this->_controller = 'customer_address_attribute';
+
+ parent::__construct();
+
+ if($this->getRequest()->getParam('popup')) {
+ $this->_removeButton('back');
+ $this->_addButton(
+ 'close',
+ array(
+ 'label' => Mage::helper('catalog')->__('Close Window'),
+ 'class' => 'cancel',
+ 'onclick' => 'window.close()',
+ 'level' => -1
+ )
+ );
+ } else {
+ $this->_addButton(
+ 'save_and_edit_button',
+ array(
+ 'label' => Mage::helper('catalog')->__('Save and Continue Edit'),
+ 'onclick' => 'saveAndContinueEdit()',
+ 'class' => 'save'
+ ),
+ 100
+ );
+ }
+
+ $this->_updateButton('save', 'label', Mage::helper('catalog')->__('Save Attribute'));
+ $this->_updateButton('save', 'onclick', 'saveAttribute()');
+
+ if (! Mage::registry('entity_attribute')->getIsUserDefined()) {
+ $this->_removeButton('delete');
+ } else {
+ $this->_updateButton('delete', 'label', Mage::helper('catalog')->__('Delete Attribute'));
+ }
+ }
+
+ public function getHeaderText()
+ {
+ if (Mage::registry('entity_attribute')->getId()) {
+ $frontendLabel = Mage::registry('entity_attribute')->getFrontendLabel();
+ if (is_array($frontendLabel)) {
+ $frontendLabel = $frontendLabel[0];
+ }
+ return Mage::helper('catalog')->__('Edit Customer Attribute "%s"', $this->escapeHtml($frontendLabel));
+ }
+ else {
+ return Mage::helper('catalog')->__('New Customer Attribute');
+ }
+ }
+
+ public function getValidationUrl()
+ {
+ return $this->getUrl('*/*/validate', array('_current'=>true));
+ }
+
+ public function getSaveUrl()
+ {
+ return $this->getUrl('*/'.$this->_controller.'/save', array('_current'=>true, 'back'=>null));
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Form.php
new file mode 100644
index 00000000000..49ca2b9fb18
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Form.php
@@ -0,0 +1,12 @@
+ 'edit_form', 'action' => $this->getData('action'), 'method' => 'post']);
+ $form->setUseContainer(true);
+ $this->setForm($form);
+ return parent::_prepareForm();
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tab/Main.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tab/Main.php
new file mode 100644
index 00000000000..4f0a44abe09
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tab/Main.php
@@ -0,0 +1,71 @@
+getAttributeObject();
+ $form = $this->getForm();
+
+ // frontend properties fieldset
+ $fieldset = $form->addFieldset('front_fieldset', [
+ 'legend' => $helper->__('Frontend Properties')
+ ]);
+ $fieldset->addField('sort_order', 'text', [
+ 'name' => 'sort_order',
+ 'label' => $helper->__('Sort Order'),
+ 'title' => $helper->__('Sort Order'),
+ 'class' => 'validate-digits'
+ ]);
+
+ $fieldset->addField('used_in_forms', 'multiselect', array(
+ 'name' => 'used_in_forms',
+ 'label' => $helper->__('Forms to Use In'),
+ 'title' => $helper->__('Forms to Use In'),
+ 'value' => $attribute->getUsedInForms(),
+ 'can_be_empty' => true,
+ 'values' => [
+ [
+ 'label' => Mage::helper('customer')->__('Customer Address Registration'),
+ 'value' => 'customer_register_address'
+ ],
+ [
+ 'label' => Mage::helper('customer')->__('Customer Account Address'),
+ 'value' => 'customer_address_edit'
+ ]
+ ]
+ ))->setSize(4);
+
+ Mage::dispatchEvent('adminhtml_customer_address_attribute_edit_prepare_form', array(
+ 'form' => $form,
+ 'attribute' => $attribute
+ ));
+
+ return $this;
+ }
+
+ public function getTabLabel()
+ {
+ return Mage::helper('customer')->__('Properties');
+ }
+
+ public function getTabTitle()
+ {
+ return Mage::helper('customer')->__('Properties');
+ }
+
+ public function canShowTab()
+ {
+ return true;
+ }
+
+ public function isHidden()
+ {
+ return false;
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tab/Options.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tab/Options.php
new file mode 100644
index 00000000000..236c7614a4a
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tab/Options.php
@@ -0,0 +1,27 @@
+__('Manage Label / Options');
+ }
+
+ public function getTabTitle()
+ {
+ return Mage::helper('customer')->__('Properties');
+ }
+
+ public function canShowTab()
+ {
+ return true;
+ }
+
+ public function isHidden()
+ {
+ return false;
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tabs.php
new file mode 100644
index 00000000000..d92d51273c0
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Edit/Tabs.php
@@ -0,0 +1,12 @@
+setId('customer_address_attribute_tabs');
+ $this->setDestElementId('edit_form');
+ $this->setTitle(Mage::helper('customer')->__('Attribute Information'));
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Grid.php b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Grid.php
new file mode 100644
index 00000000000..0a7d10bd756
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Address/Attribute/Grid.php
@@ -0,0 +1,63 @@
+addVisibleFilter();
+ $this->setCollection($collection);
+
+ return parent::_prepareCollection();
+ }
+
+ protected function _prepareColumns()
+ {
+ parent::_prepareColumns();
+
+ $this->addColumn('is_visible', [
+ 'header' => Mage::helper('customer')->__('Visible on Frontend'),
+ 'sortable' => true,
+ 'index' => 'is_visible',
+ 'align' => 'center',
+ 'type' => 'options',
+ 'options' => [
+ '1' => Mage::helper('customer')->__('Yes'),
+ '0' => Mage::helper('customer')->__('No')
+ ]
+ ]);
+
+ $this->addColumn('sort_order', array(
+ 'header' => Mage::helper('customer')->__('Sort Order'),
+ 'sortable' => true,
+ 'index' => 'sort_order',
+ 'align' => 'center'
+ ));
+
+ return $this;
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute.php
new file mode 100644
index 00000000000..f9332165963
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute.php
@@ -0,0 +1,36 @@
+_controller = 'customer_attribute';
+ $this->_headerText = Mage::helper('customer')->__('Manage Customer Attributes');
+ $this->_addButtonLabel = Mage::helper('customer')->__('Add New Attribute');
+ parent::__construct();
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit.php
new file mode 100644
index 00000000000..eaae3e7e760
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit.php
@@ -0,0 +1,92 @@
+_objectId = 'attribute_id';
+ $this->_controller = 'customer_attribute';
+
+ parent::__construct();
+
+ if($this->getRequest()->getParam('popup')) {
+ $this->_removeButton('back');
+ $this->_addButton(
+ 'close',
+ array(
+ 'label' => Mage::helper('catalog')->__('Close Window'),
+ 'class' => 'cancel',
+ 'onclick' => 'window.close()',
+ 'level' => -1
+ )
+ );
+ } else {
+ $this->_addButton(
+ 'save_and_edit_button',
+ array(
+ 'label' => Mage::helper('catalog')->__('Save and Continue Edit'),
+ 'onclick' => 'saveAndContinueEdit()',
+ 'class' => 'save'
+ ),
+ 100
+ );
+ }
+
+ $this->_updateButton('save', 'label', Mage::helper('catalog')->__('Save Attribute'));
+ $this->_updateButton('save', 'onclick', 'saveAttribute()');
+
+ if (! Mage::registry('entity_attribute')->getIsUserDefined()) {
+ $this->_removeButton('delete');
+ } else {
+ $this->_updateButton('delete', 'label', Mage::helper('catalog')->__('Delete Attribute'));
+ }
+ }
+
+ public function getHeaderText()
+ {
+ if (Mage::registry('entity_attribute')->getId()) {
+ $frontendLabel = Mage::registry('entity_attribute')->getFrontendLabel();
+ if (is_array($frontendLabel)) {
+ $frontendLabel = $frontendLabel[0];
+ }
+ return Mage::helper('catalog')->__('Edit Customer Attribute "%s"', $this->escapeHtml($frontendLabel));
+ }
+ else {
+ return Mage::helper('catalog')->__('New Customer Attribute');
+ }
+ }
+
+ public function getValidationUrl()
+ {
+ return $this->getUrl('*/*/validate', array('_current'=>true));
+ }
+
+ public function getSaveUrl()
+ {
+ return $this->getUrl('*/'.$this->_controller.'/save', array('_current'=>true, 'back'=>null));
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Form.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Form.php
new file mode 100644
index 00000000000..1a45286e437
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Form.php
@@ -0,0 +1,12 @@
+ 'edit_form', 'action' => $this->getData('action'), 'method' => 'post']);
+ $form->setUseContainer(true);
+ $this->setForm($form);
+ return parent::_prepareForm();
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tab/Main.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tab/Main.php
new file mode 100644
index 00000000000..8253d02b4f4
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tab/Main.php
@@ -0,0 +1,73 @@
+getAttributeObject();
+ $form = $this->getForm();
+
+ // frontend properties fieldset
+ $fieldset = $form->addFieldset('front_fieldset', [
+ 'legend' => $helper->__('Frontend Properties')
+ ]);
+ $fieldset->addField('sort_order', 'text', [
+ 'name' => 'sort_order',
+ 'label' => $helper->__('Sort Order'),
+ 'title' => $helper->__('Sort Order'),
+ 'class' => 'validate-digits'
+ ]);
+
+ $fieldset->addField('used_in_forms', 'multiselect', array(
+ 'name' => 'used_in_forms',
+ 'label' => $helper->__('Forms to Use In'),
+ 'title' => $helper->__('Forms to Use In'),
+ 'value' => $attribute->getUsedInForms(),
+ 'can_be_empty' => true,
+ 'values' => [
+ [
+ 'label' => $helper->__('Customer Checkout Register'),
+ 'value' => 'checkout_register'
+ ], [
+ 'label' => $helper->__('Customer Registration'),
+ 'value' => 'customer_account_create'
+ ], [
+ 'label' => $helper->__('Customer Account Edit'),
+ 'value' => 'customer_account_edit'
+ ]
+ ]
+ ))->setSize(4);
+
+ Mage::dispatchEvent('adminhtml_customer_attribute_edit_prepare_form', array(
+ 'form' => $form,
+ 'attribute' => $attribute
+ ));
+
+ return $this;
+ }
+
+ public function getTabLabel()
+ {
+ return Mage::helper('customer')->__('Properties');
+ }
+
+ public function getTabTitle()
+ {
+ return Mage::helper('customer')->__('Properties');
+ }
+
+ public function canShowTab()
+ {
+ return true;
+ }
+
+ public function isHidden()
+ {
+ return false;
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tab/Options.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tab/Options.php
new file mode 100644
index 00000000000..ebe1c2fd260
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tab/Options.php
@@ -0,0 +1,27 @@
+__('Manage Label / Options');
+ }
+
+ public function getTabTitle()
+ {
+ return Mage::helper('customer')->__('Properties');
+ }
+
+ public function canShowTab()
+ {
+ return true;
+ }
+
+ public function isHidden()
+ {
+ return false;
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tabs.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tabs.php
new file mode 100644
index 00000000000..f008e5d3a7f
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Edit/Tabs.php
@@ -0,0 +1,12 @@
+setId('customer_attribute_tabs');
+ $this->setDestElementId('edit_form');
+ $this->setTitle(Mage::helper('customer')->__('Attribute Information'));
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Grid.php b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Grid.php
new file mode 100644
index 00000000000..665d6fde316
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/Block/Customer/Attribute/Grid.php
@@ -0,0 +1,63 @@
+addVisibleFilter();
+ $this->setCollection($collection);
+
+ return parent::_prepareCollection();
+ }
+
+ protected function _prepareColumns()
+ {
+ parent::_prepareColumns();
+
+ $this->addColumn('is_visible', [
+ 'header' => Mage::helper('customer')->__('Visible on Frontend'),
+ 'sortable' => true,
+ 'index' => 'is_visible',
+ 'align' => 'center',
+ 'type' => 'options',
+ 'options' => [
+ '1' => Mage::helper('customer')->__('Yes'),
+ '0' => Mage::helper('customer')->__('No')
+ ]
+ ]);
+
+ $this->addColumn('sort_order', array(
+ 'header' => Mage::helper('customer')->__('Sort Order'),
+ 'sortable' => true,
+ 'index' => 'sort_order',
+ 'align' => 'center'
+ ));
+
+ return $this;
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/controllers/Customer/Address/AttributeController.php b/app/code/core/Mage/Adminhtml/controllers/Customer/Address/AttributeController.php
new file mode 100644
index 00000000000..2326b82a005
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/controllers/Customer/Address/AttributeController.php
@@ -0,0 +1,343 @@
+_setForcedFormKeyActions('delete');
+ parent::preDispatch();
+ $this->_entityTypeId = Mage::getModel('eav/entity')->setType(Mage_Customer_Model_Address::ENTITY)->getTypeId();
+ return $this;
+ }
+
+ protected function _initAction()
+ {
+ $this
+ ->_title($this->__('Customer'))
+ ->_title($this->__('Attributes'))
+ ->_title($this->__('Manage Customer Address Attributes'));
+
+ if($this->getRequest()->getParam('popup')) {
+ $this->loadLayout('popup');
+ } else {
+ $this->loadLayout()
+ ->_setActiveMenu('customer/attributes')
+ ->_addBreadcrumb(Mage::helper('customer')->__('Customer'), Mage::helper('customer')->__('Customer'))
+ ->_addBreadcrumb(
+ Mage::helper('catalog')->__('Manage Customer Address Attributes'),
+ Mage::helper('catalog')->__('Manage Customer Address Attributes'))
+ ;
+ }
+ return $this;
+ }
+
+ public function indexAction()
+ {
+ $this->_initAction()
+ ->_addContent($this->getLayout()->createBlock('adminhtml/customer_address_attribute'))
+ ->renderLayout();
+ }
+
+ public function newAction()
+ {
+ $this->addActionLayoutHandles();
+ $this->_forward('edit');
+ }
+
+ public function editAction()
+ {
+ $id = $this->getRequest()->getParam('attribute_id');
+ $model = Mage::getModel('customer/attribute')
+ ->setEntityTypeId($this->_entityTypeId);
+
+ if ($id) {
+ $model->load($id);
+ if (!$model->getId()) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('This attribute no longer exists'));
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ // entity type check
+ if ($model->getEntityTypeId() != $this->_entityTypeId) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('This attribute cannot be edited.'));
+ $this->_redirect('*/*/');
+ return;
+ }
+ }
+
+ // set entered data if was error when we do save
+ $data = Mage::getSingleton('adminhtml/session')->getAttributeData(true);
+ if (!empty($data)) {
+ $model->addData($data);
+ }
+
+ Mage::register('entity_attribute', $model);
+ $this->_initAction();
+ $this->_title($id ? $model->getName() : $this->__('New Attribute'));
+ $item = $id ? Mage::helper('customer')->__('Edit Customer Attribute')
+ : Mage::helper('customer')->__('New Customer Attribute');
+ $this->_addBreadcrumb($item, $item);
+ $this->renderLayout();
+ }
+
+ public function validateAction()
+ {
+ $response = new Varien_Object();
+ $response->setError(false);
+
+ $attributeCode = $this->getRequest()->getParam('attribute_code');
+ $attributeId = $this->getRequest()->getParam('attribute_id');
+ $attribute = Mage::getModel('customer/attribute')
+ ->loadByCode($this->_entityTypeId, $attributeCode);
+
+ if ($attribute->getId() && !$attributeId) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('Attribute with the same code already exists'));
+ $this->_initLayoutMessages('adminhtml/session');
+ $response->setError(true);
+ $response->setMessage($this->getLayout()->getMessagesBlock()->getGroupedHtml());
+ }
+
+ $this->getResponse()->setBody($response->toJson());
+ }
+
+ /**
+ * Get list of allowed text formatted as array
+ *
+ * @return array
+ */
+ protected function _getAllowedTags()
+ {
+ return explode(',', Mage::getStoreConfig(self::XML_PATH_ALLOWED_TAGS));
+ }
+
+ /**
+ * Filter post data
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function _filterPostData($data)
+ {
+ if ($data) {
+ /** @var Mage_Customer_Helper_Data $helper */
+ $helper = Mage::helper('customer');
+ //labels
+ $data['frontend_label'] = (array) $data['frontend_label'];
+ foreach ($data['frontend_label'] as & $value) {
+ if ($value) {
+ $value = $helper->stripTags($value);
+ }
+ }
+
+ if (!empty($data['option']) && !empty($data['option']['value']) && is_array($data['option']['value'])) {
+ $allowableTags = isset($data['is_html_allowed_on_front']) && $data['is_html_allowed_on_front']
+ ? sprintf('<%s>', implode('><', $this->_getAllowedTags())) : null;
+ foreach ($data['option']['value'] as $key => $values) {
+ foreach ($values as $storeId => $storeLabel) {
+ $data['option']['value'][$key][$storeId]
+ = $helper->stripTags($storeLabel, $allowableTags);
+ }
+ }
+ }
+ }
+ return $data;
+ }
+
+ public function saveAction()
+ {
+ $data = $this->getRequest()->getPost();
+ if ($data) {
+ /** @var Mage_Admin_Model_Session $session */
+ $session = Mage::getSingleton('adminhtml/session');
+
+ $redirectBack = $this->getRequest()->getParam('back', false);
+ $model = Mage::getModel('customer/attribute')
+ ->setEntityTypeId($this->_entityTypeId);
+ $helper = Mage::helper('customer');
+
+ $id = $this->getRequest()->getParam('attribute_id');
+
+ //validate attribute_code
+ if (isset($data['attribute_code'])) {
+ $validatorAttrCode = new Zend_Validate_Regex(array('pattern' => '/^(?!event$)[a-z][a-z_0-9]{1,254}$/'));
+ if (!$validatorAttrCode->isValid($data['attribute_code'])) {
+ $session->addError(
+ Mage::helper('customer')->__('Attribute code is invalid. Please use only letters (a-z), numbers (0-9) or underscore(_) in this field, first character should be a letter. Do not use "event" for an attribute code.')
+ );
+ $this->_redirect('*/*/edit', array('attribute_id' => $id, '_current' => true));
+ return;
+ }
+ }
+
+ //validate frontend_input
+ if (isset($data['frontend_input'])) {
+ /** @var Mage_Eav_Model_Adminhtml_System_Config_Source_Inputtype_Validator $validatorInputType */
+ $validatorInputType = Mage::getModel('eav/adminhtml_system_config_source_inputtype_validator');
+ if (!$validatorInputType->isValid($data['frontend_input'])) {
+ foreach ($validatorInputType->getMessages() as $message) {
+ $session->addError($message);
+ }
+ $this->_redirect('*/*/edit', array('attribute_id' => $id, '_current' => true));
+ return;
+ }
+ }
+
+ if ($id) {
+ $model->load($id);
+
+ if (!$model->getId()) {
+ $session->addError($helper->__('This Attribute no longer exists'));
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ // entity type check
+ if ($model->getEntityTypeId() != $this->_entityTypeId) {
+ $session->addError($helper->__('This attribute cannot be updated.'));
+ $session->setAttributeData($data);
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ $data['backend_model'] = $model->getBackendModel();
+ $data['attribute_code'] = $model->getAttributeCode();
+ $data['is_user_defined'] = $model->getIsUserDefined();
+ $data['frontend_input'] = $model->getFrontendInput();
+ } else {
+ $data['source_model'] = $helper->getAttributeSourceModelByInputType($data['frontend_input']);
+ $data['backend_model'] = $helper->getAttributeBackendModelByInputType($data['frontend_input']);
+ }
+
+ if (!isset($data['is_configurable'])) {
+ $data['is_configurable'] = 0;
+ }
+
+ if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) {
+ $data['backend_type'] = $model->getBackendTypeByInput($data['frontend_input']);
+ }
+
+ $defaultValueField = $model->getDefaultValueByInput($data['frontend_input']);
+ if ($defaultValueField) {
+ $data['default_value'] = $this->getRequest()->getParam($defaultValueField);
+ }
+
+ if(!isset($data['apply_to'])) {
+ $data['apply_to'] = array();
+ }
+
+ if ($model) {
+ $data['entity_type_id'] = $model->getEntityTypeId();
+ }
+
+ //filter
+ $data = $this->_filterPostData($data);
+ $model->addData($data);
+
+ if (!$id) {
+ $model->setEntityTypeId($this->_entityTypeId);
+ $model->setIsUserDefined(1);
+ }
+
+ try {
+ $model->save();
+ $session->addSuccess($helper->__('The product attribute has been saved.'));
+
+ /**
+ * Clear translation cache because attribute labels are stored in translation
+ */
+ Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG));
+ $session->setAttributeData(false);
+ if ($this->getRequest()->getParam('popup')) {
+ $this->_redirect('adminhtml/customer/addAttribute', array(
+ 'id' => $this->getRequest()->getParam('customer'),
+ 'attribute'=> $model->getId(),
+ '_current' => true
+ ));
+ } elseif ($redirectBack) {
+ $this->_redirect('*/*/edit', array('attribute_id' => $model->getId(),'_current'=>true));
+ } else {
+ $this->_redirect('*/*/', array());
+ }
+ return;
+ } catch (Exception $e) {
+ $session->addError($e->getMessage());
+ $session->setAttributeData($data);
+ $this->_redirect('*/*/edit', array('attribute_id' => $id, '_current' => true));
+ return;
+ }
+ }
+ $this->_redirect('*/*/');
+ }
+
+ public function deleteAction()
+ {
+ if ($id = $this->getRequest()->getParam('attribute_id')) {
+ $model = Mage::getModel('customer/attribute')
+ ->setEntityTypeId($this->_entityTypeId);
+
+ // entity type check
+ $model->load($id);
+ if ($model->getEntityTypeId() != $this->_entityTypeId || !$model->getIsUserDefined()) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('This attribute cannot be deleted.'));
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ try {
+ $model->delete();
+ Mage::getSingleton('adminhtml/session')->addSuccess(
+ Mage::helper('customer')->__('The product attribute has been deleted.'));
+ $this->_redirect('*/*/');
+ return;
+ } catch (Exception $e) {
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
+ $this->_redirect('*/*/edit', array('attribute_id' => $this->getRequest()->getParam('attribute_id')));
+ return;
+ }
+ }
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('Unable to find an attribute to delete.'));
+ $this->_redirect('*/*/');
+ }
+
+ protected function _isAllowed()
+ {
+ return Mage::getSingleton('admin/session')->isAllowed('customer/attributes/customer_address_attributes');
+ }
+}
diff --git a/app/code/core/Mage/Adminhtml/controllers/Customer/AttributeController.php b/app/code/core/Mage/Adminhtml/controllers/Customer/AttributeController.php
new file mode 100644
index 00000000000..8c97b01f778
--- /dev/null
+++ b/app/code/core/Mage/Adminhtml/controllers/Customer/AttributeController.php
@@ -0,0 +1,343 @@
+_setForcedFormKeyActions('delete');
+ parent::preDispatch();
+ $this->_entityTypeId = Mage::getModel('eav/entity')->setType(Mage_Customer_Model_Customer::ENTITY)->getTypeId();
+ return $this;
+ }
+
+ protected function _initAction()
+ {
+ $this
+ ->_title($this->__('Customer'))
+ ->_title($this->__('Attributes'))
+ ->_title($this->__('Manage Customer Attributes'));
+
+ if($this->getRequest()->getParam('popup')) {
+ $this->loadLayout('popup');
+ } else {
+ $this->loadLayout()
+ ->_setActiveMenu('customer/attributes')
+ ->_addBreadcrumb(Mage::helper('customer')->__('Customer'), Mage::helper('customer')->__('Customer'))
+ ->_addBreadcrumb(
+ Mage::helper('customer')->__('Manage Customer Attributes'),
+ Mage::helper('customer')->__('Manage Customer Attributes'))
+ ;
+ }
+ return $this;
+ }
+
+ public function indexAction()
+ {
+ $this->_initAction()
+ ->_addContent($this->getLayout()->createBlock('adminhtml/customer_attribute'))
+ ->renderLayout();
+ }
+
+ public function newAction()
+ {
+ $this->addActionLayoutHandles();
+ $this->_forward('edit');
+ }
+
+ public function editAction()
+ {
+ $id = $this->getRequest()->getParam('attribute_id');
+ $model = Mage::getModel('customer/attribute')
+ ->setEntityTypeId($this->_entityTypeId);
+
+ if ($id) {
+ $model->load($id);
+ if (!$model->getId()) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('This attribute no longer exists'));
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ // entity type check
+ if ($model->getEntityTypeId() != $this->_entityTypeId) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('This attribute cannot be edited.'));
+ $this->_redirect('*/*/');
+ return;
+ }
+ }
+
+ // set entered data if was error when we do save
+ $data = Mage::getSingleton('adminhtml/session')->getAttributeData(true);
+ if (!empty($data)) {
+ $model->addData($data);
+ }
+
+ Mage::register('entity_attribute', $model);
+ $this->_initAction();
+ $this->_title($id ? $model->getName() : $this->__('New Attribute'));
+ $item = $id ? Mage::helper('customer')->__('Edit Customer Attribute')
+ : Mage::helper('customer')->__('New Customer Attribute');
+ $this->_addBreadcrumb($item, $item);
+ $this->renderLayout();
+ }
+
+ public function validateAction()
+ {
+ $response = new Varien_Object();
+ $response->setError(false);
+
+ $attributeCode = $this->getRequest()->getParam('attribute_code');
+ $attributeId = $this->getRequest()->getParam('attribute_id');
+ $attribute = Mage::getModel('customer/attribute')
+ ->loadByCode($this->_entityTypeId, $attributeCode);
+
+ if ($attribute->getId() && !$attributeId) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('Attribute with the same code already exists'));
+ $this->_initLayoutMessages('adminhtml/session');
+ $response->setError(true);
+ $response->setMessage($this->getLayout()->getMessagesBlock()->getGroupedHtml());
+ }
+
+ $this->getResponse()->setBody($response->toJson());
+ }
+
+ /**
+ * Get list of allowed text formatted as array
+ *
+ * @return array
+ */
+ protected function _getAllowedTags()
+ {
+ return explode(',', Mage::getStoreConfig(self::XML_PATH_ALLOWED_TAGS));
+ }
+
+ /**
+ * Filter post data
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function _filterPostData($data)
+ {
+ if ($data) {
+ /** @var Mage_Customer_Helper_Data $helper */
+ $helper = Mage::helper('customer');
+ //labels
+ $data['frontend_label'] = (array) $data['frontend_label'];
+ foreach ($data['frontend_label'] as & $value) {
+ if ($value) {
+ $value = $helper->stripTags($value);
+ }
+ }
+
+ if (!empty($data['option']) && !empty($data['option']['value']) && is_array($data['option']['value'])) {
+ $allowableTags = isset($data['is_html_allowed_on_front']) && $data['is_html_allowed_on_front']
+ ? sprintf('<%s>', implode('><', $this->_getAllowedTags())) : null;
+ foreach ($data['option']['value'] as $key => $values) {
+ foreach ($values as $storeId => $storeLabel) {
+ $data['option']['value'][$key][$storeId]
+ = $helper->stripTags($storeLabel, $allowableTags);
+ }
+ }
+ }
+ }
+ return $data;
+ }
+
+ public function saveAction()
+ {
+ $data = $this->getRequest()->getPost();
+ if ($data) {
+ /** @var Mage_Admin_Model_Session $session */
+ $session = Mage::getSingleton('adminhtml/session');
+
+ $redirectBack = $this->getRequest()->getParam('back', false);
+ $model = Mage::getModel('customer/attribute')
+ ->setEntityTypeId($this->_entityTypeId);
+ $helper = Mage::helper('customer');
+
+ $id = $this->getRequest()->getParam('attribute_id');
+
+ //validate attribute_code
+ if (isset($data['attribute_code'])) {
+ $validatorAttrCode = new Zend_Validate_Regex(array('pattern' => '/^(?!event$)[a-z][a-z_0-9]{1,254}$/'));
+ if (!$validatorAttrCode->isValid($data['attribute_code'])) {
+ $session->addError(
+ Mage::helper('customer')->__('Attribute code is invalid. Please use only letters (a-z), numbers (0-9) or underscore(_) in this field, first character should be a letter. Do not use "event" for an attribute code.')
+ );
+ $this->_redirect('*/*/edit', array('attribute_id' => $id, '_current' => true));
+ return;
+ }
+ }
+
+ //validate frontend_input
+ if (isset($data['frontend_input'])) {
+ /** @var Mage_Eav_Model_Adminhtml_System_Config_Source_Inputtype_Validator $validatorInputType */
+ $validatorInputType = Mage::getModel('eav/adminhtml_system_config_source_inputtype_validator');
+ if (!$validatorInputType->isValid($data['frontend_input'])) {
+ foreach ($validatorInputType->getMessages() as $message) {
+ $session->addError($message);
+ }
+ $this->_redirect('*/*/edit', array('attribute_id' => $id, '_current' => true));
+ return;
+ }
+ }
+
+ if ($id) {
+ $model->load($id);
+
+ if (!$model->getId()) {
+ $session->addError($helper->__('This Attribute no longer exists'));
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ // entity type check
+ if ($model->getEntityTypeId() != $this->_entityTypeId) {
+ $session->addError($helper->__('This attribute cannot be updated.'));
+ $session->setAttributeData($data);
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ $data['backend_model'] = $model->getBackendModel();
+ $data['attribute_code'] = $model->getAttributeCode();
+ $data['is_user_defined'] = $model->getIsUserDefined();
+ $data['frontend_input'] = $model->getFrontendInput();
+ } else {
+ $data['source_model'] = $helper->getAttributeSourceModelByInputType($data['frontend_input']);
+ $data['backend_model'] = $helper->getAttributeBackendModelByInputType($data['frontend_input']);
+ }
+
+ if (!isset($data['is_configurable'])) {
+ $data['is_configurable'] = 0;
+ }
+
+ if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) {
+ $data['backend_type'] = $model->getBackendTypeByInput($data['frontend_input']);
+ }
+
+ $defaultValueField = $model->getDefaultValueByInput($data['frontend_input']);
+ if ($defaultValueField) {
+ $data['default_value'] = $this->getRequest()->getParam($defaultValueField);
+ }
+
+ if(!isset($data['apply_to'])) {
+ $data['apply_to'] = array();
+ }
+
+ if ($model) {
+ $data['entity_type_id'] = $model->getEntityTypeId();
+ }
+
+ //filter
+ $data = $this->_filterPostData($data);
+ $model->addData($data);
+
+ if (!$id) {
+ $model->setEntityTypeId($this->_entityTypeId);
+ $model->setIsUserDefined(1);
+ }
+
+ try {
+ $model->save();
+ $session->addSuccess($helper->__('The product attribute has been saved.'));
+
+ /**
+ * Clear translation cache because attribute labels are stored in translation
+ */
+ Mage::app()->cleanCache(array(Mage_Core_Model_Translate::CACHE_TAG));
+ $session->setAttributeData(false);
+ if ($this->getRequest()->getParam('popup')) {
+ $this->_redirect('adminhtml/customer/addAttribute', array(
+ 'id' => $this->getRequest()->getParam('customer'),
+ 'attribute'=> $model->getId(),
+ '_current' => true
+ ));
+ } elseif ($redirectBack) {
+ $this->_redirect('*/*/edit', array('attribute_id' => $model->getId(),'_current'=>true));
+ } else {
+ $this->_redirect('*/*/', array());
+ }
+ return;
+ } catch (Exception $e) {
+ $session->addError($e->getMessage());
+ $session->setAttributeData($data);
+ $this->_redirect('*/*/edit', array('attribute_id' => $id, '_current' => true));
+ return;
+ }
+ }
+ $this->_redirect('*/*/');
+ }
+
+ public function deleteAction()
+ {
+ if ($id = $this->getRequest()->getParam('attribute_id')) {
+ $model = Mage::getModel('customer/attribute')
+ ->setEntityTypeId($this->_entityTypeId);
+
+ // entity type check
+ $model->load($id);
+ if ($model->getEntityTypeId() != $this->_entityTypeId || !$model->getIsUserDefined()) {
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('This attribute cannot be deleted.'));
+ $this->_redirect('*/*/');
+ return;
+ }
+
+ try {
+ $model->delete();
+ Mage::getSingleton('adminhtml/session')->addSuccess(
+ Mage::helper('customer')->__('The customer attribute has been deleted.'));
+ $this->_redirect('*/*/');
+ return;
+ } catch (Exception $e) {
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
+ $this->_redirect('*/*/edit', array('attribute_id' => $this->getRequest()->getParam('attribute_id')));
+ return;
+ }
+ }
+ Mage::getSingleton('adminhtml/session')->addError(
+ Mage::helper('customer')->__('Unable to find an attribute to delete.'));
+ $this->_redirect('*/*/');
+ }
+
+ protected function _isAllowed()
+ {
+ return Mage::getSingleton('admin/session')->isAllowed('customer/attributes/customer_attributes');
+ }
+}
diff --git a/app/code/core/Mage/Customer/Helper/Data.php b/app/code/core/Mage/Customer/Helper/Data.php
index 9ec531ee12d..807924c0916 100644
--- a/app/code/core/Mage/Customer/Helper/Data.php
+++ b/app/code/core/Mage/Customer/Helper/Data.php
@@ -763,4 +763,64 @@ protected function _createVatNumberValidationSoapClient($trace = false)
{
return new SoapClient(self::VAT_VALIDATION_WSDL_URL, array('trace' => $trace));
}
+
+ /**
+ * Return information array of product attribute input types
+ * Only a small number of settings returned, so we won't break anything in current dataflow
+ * As soon as development process goes on we need to add there all possible settings
+ *
+ * @param string $inputType
+ * @return array
+ */
+ public function getAttributeInputTypes($inputType = null)
+ {
+ /**
+ * @todo specify there all relations for properties depending on input type
+ */
+ $inputTypes = array(
+ 'multiselect' => array(
+ 'backend_model' => 'eav/entity_attribute_backend_array'
+ ),
+ 'boolean' => array(
+ 'source_model' => 'eav/entity_attribute_source_boolean'
+ )
+ );
+
+ if (is_null($inputType)) {
+ return $inputTypes;
+ } elseif (isset($inputTypes[$inputType])) {
+ return $inputTypes[$inputType];
+ }
+ return array();
+ }
+
+ /**
+ * Return default attribute source model by input type
+ *
+ * @param string $inputType
+ * @return string|null
+ */
+ public function getAttributeSourceModelByInputType($inputType)
+ {
+ $inputTypes = $this->getAttributeInputTypes();
+ if (!empty($inputTypes[$inputType]['source_model'])) {
+ return $inputTypes[$inputType]['source_model'];
+ }
+ return null;
+ }
+
+ /**
+ * Return default attribute backend model by input type
+ *
+ * @param string $inputType
+ * @return string|null
+ */
+ public function getAttributeBackendModelByInputType($inputType)
+ {
+ $inputTypes = $this->getAttributeInputTypes();
+ if (!empty($inputTypes[$inputType]['backend_model'])) {
+ return $inputTypes[$inputType]['backend_model'];
+ }
+ return null;
+ }
}
diff --git a/app/code/core/Mage/Customer/Model/Address.php b/app/code/core/Mage/Customer/Model/Address.php
index 27bd1931f59..38d47689281 100644
--- a/app/code/core/Mage/Customer/Model/Address.php
+++ b/app/code/core/Mage/Customer/Model/Address.php
@@ -41,6 +41,8 @@
*/
class Mage_Customer_Model_Address extends Mage_Customer_Model_Address_Abstract
{
+ const ENTITY = 'customer_address';
+
protected $_customer;
protected function _construct()
diff --git a/app/code/core/Mage/Customer/Model/Customer.php b/app/code/core/Mage/Customer/Model/Customer.php
index a1496391f5f..365f80d6ee1 100644
--- a/app/code/core/Mage/Customer/Model/Customer.php
+++ b/app/code/core/Mage/Customer/Model/Customer.php
@@ -121,6 +121,8 @@
*/
class Mage_Customer_Model_Customer extends Mage_Core_Model_Abstract
{
+ const ENTITY = 'customer';
+
/**#@+
* Configuration pathes for email templates and identities
*/
@@ -155,7 +157,7 @@ class Mage_Customer_Model_Customer extends Mage_Core_Model_Abstract
const SUBSCRIBED_NO = 'no';
/**#@-*/
- const CACHE_TAG = 'customer';
+ const CACHE_TAG = self::ENTITY;
/**
* Minimum Password Length
@@ -178,14 +180,14 @@ class Mage_Customer_Model_Customer extends Mage_Core_Model_Abstract
*
* @var string
*/
- protected $_eventPrefix = 'customer';
+ protected $_eventPrefix = self::ENTITY;
/**
* Name of the event object
*
* @var string
*/
- protected $_eventObject = 'customer';
+ protected $_eventObject = self::ENTITY;
/**
* List of errors
diff --git a/app/code/core/Mage/Customer/etc/adminhtml.xml b/app/code/core/Mage/Customer/etc/adminhtml.xml
index 40363e19d8d..d80857339d9 100644
--- a/app/code/core/Mage/Customer/etc/adminhtml.xml
+++ b/app/code/core/Mage/Customer/etc/adminhtml.xml
@@ -30,7 +30,6 @@