├── CHANGELOG.md ├── i18n ├── de_DE.csv ├── en_GB.csv ├── en_US.csv └── fr_FR.csv ├── registration.php ├── etc ├── adminhtml │ ├── events.xml │ ├── routes.xml │ └── system.xml ├── module.xml ├── di.xml ├── routes.xml ├── config.xml ├── acl.xml └── fieldset.xml ├── view ├── frontend │ ├── requirejs-config.js │ ├── layout │ │ ├── customer_account_edit.xml │ │ ├── customer_account_forgotpassword.xml │ │ ├── customer_account_create.xml │ │ └── customer_account_login.xml │ ├── templates │ │ ├── widget │ │ │ └── username.phtml │ │ └── form │ │ │ ├── forgotpassword.phtml │ │ │ ├── login.phtml │ │ │ ├── edit.phtml │ │ │ └── register.phtml │ └── web │ │ ├── template │ │ ├── form │ │ │ └── element │ │ │ │ └── email.html │ │ └── authentication.html │ │ └── js │ │ └── view │ │ └── form │ │ └── element │ │ └── email.js └── adminhtml │ └── templates │ └── config │ └── generate.phtml ├── composer.json ├── Model ├── Config │ ├── Source │ │ └── Inputvalidation.php │ └── Share.php ├── Generate │ └── Flag.php └── Event │ ├── AddToCollection.php │ └── ChangeEavAttribute.php ├── Controller ├── Adminhtml │ ├── Sync.php │ └── Sync │ │ ├── Status.php │ │ └── Generate.php └── Account │ └── ForgotPasswordPost.php ├── Setup ├── Uninstall.php ├── InstallData.php ├── UpgradeData.php └── InstallSchema.php ├── phpunit.xml.dist ├── README.md ├── Block ├── Config │ └── Form │ │ └── Field │ │ └── Generate.php └── Widget │ └── Username.php ├── Test └── Helper │ └── CustomerTest.php ├── Helper └── Customer.php ├── Plugin └── Model │ └── ResourceModel │ └── CustomerRepositoryPlugin.php └── LICENSE.txt /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### Changelog 2 | -------------------------------------------------------------------------------- /i18n/de_DE.csv: -------------------------------------------------------------------------------- 1 | "This account is disabled.","Dieses Benutzerkonto ist deaktiviert." 2 | "Username","Benutzername" 3 | "Email Address/Username","E-Mail-Adresse/Benutzername" 4 | "Email/Username:","E-Mail-Adresse/Benutzername:" -------------------------------------------------------------------------------- /i18n/en_GB.csv: -------------------------------------------------------------------------------- 1 | "This account is disabled.","This account is disabled." 2 | "Username","Username" 3 | "Email Address/Username", "Email Address/Username" 4 | "'Email/Username:'","'Email/Username:'" 5 | "Username already exists","Username already exists" -------------------------------------------------------------------------------- /i18n/en_US.csv: -------------------------------------------------------------------------------- 1 | "This account is disabled.","This account is disabled." 2 | "Username","Username" 3 | "Email Address/Username", "Email Address/Username" 4 | "'Email/Username:'","'Email/Username:'" 5 | "Username already exists","Username already exists" 6 | "Change Email & Username" -------------------------------------------------------------------------------- /i18n/fr_FR.csv: -------------------------------------------------------------------------------- 1 | "This account is disabled.","Ce compte est désactivé" 2 | "Username","Nom d'utilisateur" 3 | "Email Address/Username", "Adresse email / Nom d'utilisateur" 4 | "'Email/Username:'","'Adresse Email / Nom d\utilisateur:'" 5 | "Username already exists","Ce nom d'utilisateur existe déjà" -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /view/frontend/requirejs-config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | map: { 3 | '*': { 4 | 'Magento_Checkout/template/authentication.html': 5 | 'Diglin_Username/template/authentication.html' 6 | //'Magento_Checkout/form/element/email': 7 | // 'Diglin_Username/form/element/email', 8 | //'Magento_Checkout/form/element/email.html': 9 | // 'Diglin_Username/form/element/email.html' 10 | } 11 | } 12 | }; -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /etc/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 1 13 | 0 14 | 30 15 | 6 16 | default 17 | 1 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /view/frontend/layout/customer_account_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | Diglin_Username::form/edit.phtml 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /view/frontend/layout/customer_account_forgotpassword.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | Diglin_Username::form/forgotpassword.phtml 16 | 17 | 18 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "diglin/module-username", 3 | "description": "Real Username support for Magento 2", 4 | "require": { 5 | "php": "~5.5.0|~5.6.0|~7.0.0|~7.1.0", 6 | "magento/framework": "100.0.*|100.1.*", 7 | "magento/module-backend": "100.0.*|100.1.*", 8 | "magento/module-checkout": "100.0.*|100.1.*", 9 | "magento/module-config": "100.0.*|100.1.*", 10 | "magento/module-customer": "100.0.*|100.1.*", 11 | "magento/module-eav": "100.0.*|100.1.*", 12 | "magento/module-quote": "100.0.*|100.1.*", 13 | "magento/module-sales": "100.0.*|100.1.*", 14 | "magento/module-store": "100.0.*|100.1.*", 15 | "magento/module-theme": "100.0.*|100.1.*", 16 | 17 | "hoa/regex": "~1.0" 18 | }, 19 | "type": "magento2-module", 20 | "version": "2.0.0-beta", 21 | "license": [ 22 | "OSL-3.0", 23 | "AFL-3.0" 24 | ], 25 | "autoload": { 26 | "files": [ 27 | "registration.php" 28 | ], 29 | "psr-4": { 30 | "Diglin\\Username\\": "" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Model/Config/Source/Inputvalidation.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_Username 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Model\Config\Source; 12 | 13 | class Inputvalidation implements \Magento\Framework\Option\ArrayInterface 14 | { 15 | /** 16 | * Options getter 17 | * 18 | * @deprecated 19 | * @return array 20 | */ 21 | public function toOptionArray() 22 | { 23 | return [ 24 | ['value'=>'default', 'label'=> __('Default (letters, digits and _- characters)')], 25 | ['value'=>'alphanumeric', 'label'=> __('Letters and digits')], 26 | ['value'=>'alpha', 'label'=> __('Letters only')], 27 | ['value'=>'numeric', 'label'=> __('Digits only')], 28 | ['value'=>'custom', 'label'=> __('Custom (PCRE Regex)')] 29 | ]; 30 | } 31 | } -------------------------------------------------------------------------------- /view/frontend/layout/customer_account_create.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | Diglin_Username::form/register.phtml 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /view/frontend/layout/customer_account_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | Diglin_Username::form/login.phtml 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Model/Generate/Flag.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (c) 2008-2015 Diglin GmbH - Switzerland (http://www.diglin.com) 9 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 10 | */ 11 | 12 | namespace Diglin\Username\Model\Generate; 13 | 14 | /** 15 | * Class Flag 16 | * @package Diglin\Username\Model\Generate 17 | */ 18 | class Flag extends \Magento\Framework\Flag 19 | { 20 | /** 21 | * There was no generation 22 | */ 23 | const STATE_INACTIVE = 0; 24 | /** 25 | * Generation process is active 26 | */ 27 | const STATE_RUNNING = 1; 28 | /** 29 | * Generation is finished 30 | */ 31 | const STATE_FINISHED = 2; 32 | /** 33 | * Generation finished and notify message was formed 34 | */ 35 | const STATE_NOTIFIED = 3; 36 | 37 | /** 38 | * Generation flag code 39 | * 40 | * @var string 41 | */ 42 | protected $_flagCode = 'username_generate'; 43 | } 44 | -------------------------------------------------------------------------------- /etc/fieldset.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | 24 | 25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Sync.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Controller\Adminhtml; 12 | 13 | abstract class Sync extends \Magento\Backend\App\Action 14 | { 15 | /** 16 | * Authorization level of a basic admin session 17 | */ 18 | const ADMIN_USERNAME_RESOURCE = 'Diglin_Username::config_username'; 19 | 20 | /** 21 | * Return file storage singleton 22 | * 23 | * @return \Diglin\Username\Model\Generate\Flag 24 | */ 25 | protected function _getSyncSingleton() 26 | { 27 | return $this->_objectManager->get('Diglin\Username\Model\Generate\Flag'); 28 | } 29 | 30 | /** 31 | * Return synchronize process status flag 32 | * 33 | * @return \Diglin\Username\Model\Generate\Flag 34 | */ 35 | protected function _getSyncFlag() 36 | { 37 | return $this->_getSyncSingleton()->loadSelf(); 38 | } 39 | 40 | /** 41 | * @return bool 42 | */ 43 | protected function _isAllowed() 44 | { 45 | return $this->_authorization->isAllowed(static::ADMIN_USERNAME_RESOURCE); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Setup/Uninstall.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_Username 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Setup; 12 | 13 | use Magento\Customer\Model\Customer; 14 | use Magento\Framework\Setup\ModuleContextInterface; 15 | use Magento\Framework\Setup\SchemaSetupInterface; 16 | use Magento\Eav\Setup\EavSetup; 17 | 18 | /** 19 | * Class Uninstall 20 | */ 21 | class Uninstall implements \Magento\Framework\Setup\UninstallInterface 22 | { 23 | /** 24 | * @var EavSetup 25 | */ 26 | private $eavSetup; 27 | 28 | /** 29 | * InstallSchema constructor. 30 | */ 31 | public function __construct( 32 | EavSetup $eavSetup 33 | ){ 34 | $this->eavSetup = $eavSetup; 35 | } 36 | 37 | /** 38 | * @param SchemaSetupInterface $setup 39 | * @param ModuleContextInterface $context 40 | */ 41 | public function uninstall(SchemaSetupInterface $setup, ModuleContextInterface $context) 42 | { 43 | $setup->startSetup(); 44 | 45 | $this->eavSetup->removeAttribute(Customer::ENTITY, 'username'); 46 | 47 | $setup->getConnection()->dropColumn($setup->getTable('customer_grid_flat'), 'username'); 48 | $setup->getConnection()->dropColumn($setup->getTable('quote'), 'customer_username'); 49 | $setup->getConnection()->dropColumn($setup->getTable('sales_order'), 'customer_username'); 50 | 51 | $setup->endSetup(); 52 | } 53 | } -------------------------------------------------------------------------------- /Model/Event/AddToCollection.php: -------------------------------------------------------------------------------- 1 | getEvent()->getCollection(); 41 | $entity = $collection->getEntity(); 42 | if (!empty($entity) && $entity->getType() == 'customer') { 43 | $collection->addAttributeToSelect('username'); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | tests/Framework 10 | tests/Extensions 11 | tests/Runner 12 | tests/Util 13 | 14 | 15 | 16 | tests/TextUI 17 | tests/Regression 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | src 31 | 32 | src/Framework/Assert/Functions.php 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /view/frontend/templates/widget/username.phtml: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | // @codingStandardsIgnoreFile 12 | 13 | /* @var $block Diglin\Username\Block\Widget\Username */ 14 | 15 | $username = $block->getUsername(); 16 | ?> 17 |
18 | isEditable() || !$block->isEditable() && !empty($username)): ?> 19 | 20 | 21 |
22 | isEditable()): ?> 23 | getFieldParams() ?> getAttributeValidationClass('username') == 'required-entry') echo ' data-validate="{required:true}"' ?>> 28 | 29 | escapeHtml($username); ?> 30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /Model/Config/Share.php: -------------------------------------------------------------------------------- 1 | getValue(); 39 | if ($value == self::SHARE_GLOBAL) { 40 | if ($this->_customerResource->findUsernameDuplicates()) { // @todo - see how to implement the method findUsernameDuplicates with overwrite or similar (plugin) 41 | //@codingStandardsIgnoreStart 42 | throw new \Magento\Framework\Exception\LocalizedException( 43 | __('Cannot share customer accounts globally because some customer accounts with the same username exist on multiple websites and cannot be merged.') 44 | ); 45 | } 46 | } 47 | return $this; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /view/frontend/templates/form/forgotpassword.phtml: -------------------------------------------------------------------------------- 1 | helper('\Diglin\Username\Helper\Customer')->isEnabled()) { 16 | $usernameLabel = __('Email/Username'); 17 | $usernameInputType = 'text'; 18 | $usernameInputValidation = ""; 19 | } 20 | 21 | ?> 22 |
27 |
28 |
29 | 35 | getChildHtml('form_additional_info'); ?> 36 |
37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Diglin\Username module for Magento 2 - BETA # 2 | 3 | Magento module which allows your customers to use a username and not only the email address as identifier 4 | 5 | **IMPORTANT** 6 | It's a BETA. Lots of things have not been yet implemented or is a work in progress. See the issues https://github.com/diglin/Diglin_Username2/issues/created_by/diglin. For example checkout account creation with username doesn't work. 7 | 8 | ## Features 9 | 10 | - Compatible and tested with Magento version 2.0 & 2.1 11 | - Login with a username or email, it can be done from frontend during checkout or to get access to the customer account 12 | - Save a username from frontend (register account or checkout process) or from backend by editing a customer account 13 | - Prevent duplicate username 14 | - The default templates override some customer and checkout views to adapt display for login pages, checkout process and account edition in frontend. If you have a customized template, update your template with the content of the one of this module. 15 | - Configurable options to define what kind of username to support: only letters, only digits, both or default (digits, letters and special characters '-_') or even custom regex 16 | - Configurable options to set the maximum and minimum string length 17 | - Display Username of each customer in the Customer Management Grid 18 | - Allow or not the customer to edit the username in My Account in frontend 19 | - Support username when a customer wants to retrieve his forgotten password thanks to the "Forgotten Password" form 20 | - Generate usernames for customer account who don't have one, can be triggered from configuration page. Generated usernames will use current saved configuration (letters, digits, both or custom regex). 21 | 22 | ## Installation 23 | 24 | ``` 25 | cd path/to/my/magento/project 26 | composer.phar require 'diglin/module-username' 27 | bin/magento module:enable Diglin_Username 28 | bin/magento setup:upgrade 29 | bin/magento setup:di:compile 30 | ``` 31 | 32 | ## Uninstall 33 | 34 | ``` 35 | cd path/to/my/magento/project 36 | bin/magento module:uninstall -r Diglin_Username 37 | ``` 38 | 39 | ## Author 40 | 41 | * Sylvain Rayé 42 | * http://www.diglin.com/ 43 | * [@diglin_](https://twitter.com/diglin_) 44 | * [Follow me on github!](https://github.com/diglin) 45 | -------------------------------------------------------------------------------- /Setup/InstallData.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Training\CustomerComment\Setup 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Setup; 12 | 13 | use Magento\Customer\Model\Customer; 14 | use Magento\Customer\Setup\CustomerSetup; 15 | use Magento\Framework\Setup\InstallDataInterface; 16 | use Magento\Framework\Setup\ModuleContextInterface; 17 | use Magento\Framework\Setup\ModuleDataSetupInterface; 18 | use Magento\Customer\Setup\CustomerSetupFactory; 19 | 20 | /** 21 | * @codeCoverageIgnore 22 | */ 23 | class InstallData implements InstallDataInterface 24 | { 25 | /** 26 | * Customer setup factory 27 | * 28 | * @var CustomerSetupFactory 29 | */ 30 | private $customerSetupFactory; 31 | 32 | /** 33 | * Init 34 | * 35 | * @param CustomerSetupFactory $customerSetupFactory 36 | */ 37 | public function __construct(CustomerSetupFactory $customerSetupFactory) 38 | { 39 | $this->customerSetupFactory = $customerSetupFactory; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength) 45 | */ 46 | public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 47 | { 48 | /** @var CustomerSetup $customerSetup */ 49 | $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]); 50 | 51 | $setup->startSetup(); 52 | 53 | $attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'username'); 54 | 55 | $data = []; 56 | $usedInForms = [ 57 | 'adminhtml_customer', 58 | 'adminhtml_checkout', 59 | 'customer_account_edit', 60 | 'customer_account_create', 61 | 'checkout_register' 62 | ]; 63 | 64 | foreach ($usedInForms as $formCode) { 65 | $data[] = ['form_code' => $formCode, 'attribute_id' => $attribute->getId()]; 66 | } 67 | 68 | if ($data) { 69 | $setup->getConnection() 70 | ->insertMultiple($setup->getTable('customer_form_attribute'), $data); 71 | } 72 | 73 | $setup->endSetup(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Setup/UpgradeData.php: -------------------------------------------------------------------------------- 1 | fieldDataConverterFactory = $fieldDataConverterFactory; 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) 39 | { 40 | if (version_compare($context->getVersion(), "2.0.1", '<')) { 41 | $this->convertSerializedDataToJson($setup); 42 | } 43 | } 44 | 45 | /** 46 | * Convert data for the customer_eav_attribute.username from serialized to JSON format 47 | * 48 | * @param ModuleDataSetupInterface $setup 49 | * 50 | * @return void 51 | */ 52 | protected function convertSerializedDataToJson(ModuleDataSetupInterface $setup) 53 | { 54 | $tableName = 'customer_eav_attribute'; 55 | $identifierFieldName = 'attribute_id'; 56 | $serializedFieldName = 'validate_rules'; 57 | 58 | /** @var \Magento\Framework\DB\FieldDataConverter $fieldDataConverter */ 59 | $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); 60 | try { 61 | 62 | $fieldDataConverter->convert( 63 | $setup->getConnection(), 64 | $setup->getTable($tableName), 65 | $identifierFieldName, 66 | $serializedFieldName 67 | ); 68 | } catch (\Magento\Framework\DB\FieldDataConversionException $e) { 69 | //TODO add exception handler 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Block/Config/Form/Field/Generate.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_Username 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Block\Config\Form\Field; 12 | 13 | use Magento\Config\Block\System\Config\Form\Field; 14 | 15 | /** 16 | * Class Generate 17 | * @package Diglin\Username\Block\Config\Form\Field 18 | */ 19 | class Generate extends Field 20 | { 21 | /** 22 | * @var string 23 | */ 24 | protected $_template = 'Diglin_Username::config/generate.phtml'; 25 | 26 | /** 27 | * Remove scope label 28 | * 29 | * @param \Magento\Framework\Data\Form\Element\AbstractElement $element 30 | * @return string 31 | */ 32 | public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) 33 | { 34 | $element 35 | ->unsScope() 36 | ->unsCanUseWebsiteValue() 37 | ->unsCanUseDefaultValue(); 38 | 39 | return parent::render($element); 40 | } 41 | 42 | /** 43 | * Return element html 44 | * 45 | * @param \Magento\Framework\Data\Form\Element\AbstractElement $element 46 | * @return string 47 | * 48 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) 49 | */ 50 | protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element) 51 | { 52 | return $this->_toHtml(); 53 | } 54 | 55 | /** 56 | * Return ajax url for synchronize button 57 | * 58 | * @return string 59 | */ 60 | public function getAjaxSyncUrl() 61 | { 62 | return $this->getUrl('username/sync/generate'); 63 | } 64 | 65 | /** 66 | * Return ajax url for synchronize button 67 | * 68 | * @return string 69 | */ 70 | public function getAjaxStatusUpdateUrl() 71 | { 72 | return $this->getUrl('username/sync/status'); 73 | } 74 | 75 | /** 76 | * Generate generate button html 77 | * 78 | * @return string 79 | */ 80 | public function getButtonHtml() 81 | { 82 | /* @var $button \Magento\Backend\Block\Widget\Button */ 83 | $button = $this 84 | ->getLayout() 85 | ->createBlock('Magento\Backend\Block\Widget\Button') 86 | ->setData(array( 87 | 'id' => 'generate_button', 88 | 'label' => __('Generate'), 89 | )); 90 | 91 | return $button->toHtml(); 92 | } 93 | } -------------------------------------------------------------------------------- /Controller/Adminhtml/Sync/Status.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Controller\Adminhtml\Sync; 12 | 13 | 14 | use Diglin\Username\Controller\Adminhtml\Sync; 15 | use Diglin\Username\Model\Generate\Flag; 16 | use Magento\Backend\App\Action\Context; 17 | use Magento\Framework\Json\Helper\Data; 18 | 19 | /** 20 | * Class Status 21 | * @package Diglin\Username\Controller\Adminhtml\Username\Sync 22 | */ 23 | class Status extends Sync 24 | { 25 | /** 26 | * @var Data 27 | */ 28 | private $jsonHelper; 29 | 30 | /** 31 | * Status constructor. 32 | */ 33 | public function __construct( 34 | Context $context, 35 | Data $jsonHelper 36 | ) { 37 | $this->jsonHelper = $jsonHelper; 38 | parent::__construct($context); 39 | } 40 | 41 | public function execute() 42 | { 43 | $flag = $this->_getSyncFlag(); 44 | if ($flag) { 45 | $state = $flag->getState(); 46 | $flagData = $flag->getFlagData(); 47 | 48 | switch ($state) { 49 | case Flag::STATE_RUNNING: 50 | if ($flagData['total_items'] > 0) { 51 | $percent = (int)($flagData['total_items_done'] * 100 / $flagData['total_items']) . '%'; 52 | $result['message'] = __('Generating username: %s done.', $percent); 53 | } else { 54 | $result ['message'] = __('Generating...'); 55 | } 56 | break; 57 | case Flag::STATE_FINISHED: 58 | $result ['message'] = __('Generation finished'); 59 | 60 | if ($flag->getHasErrors()) { 61 | $result ['message'] .= __('Errors occurred while running. Please, check the log if enabled.'); 62 | $result ['has_errors'] = true; 63 | } 64 | $state = Flag::STATE_NOTIFIED; 65 | break; 66 | case Flag::STATE_NOTIFIED: 67 | break; 68 | default: 69 | $state = Flag::STATE_INACTIVE; 70 | break; 71 | } 72 | } else { 73 | $state = Flag::STATE_INACTIVE; 74 | } 75 | $result['state'] = $state; 76 | 77 | $this->getResponse()->setBody($this->jsonHelper->jsonEncode($result)); 78 | } 79 | } -------------------------------------------------------------------------------- /Controller/Account/ForgotPasswordPost.php: -------------------------------------------------------------------------------- 1 | resultRedirectFactory->create(); 26 | $email = (string)$this->getRequest()->getPost('email'); 27 | if ($email) { 28 | 29 | // Diglin - Commented as not needed 30 | // if (!\Zend_Validate::is($email, 'EmailAddress')) { 31 | // $this->session->setForgottenEmail($email); 32 | // $this->messageManager->addErrorMessage(__('Please correct the email address.')); 33 | // return $resultRedirect->setPath('*/*/forgotpassword'); 34 | // } 35 | 36 | try { 37 | $this->customerAccountManagement->initiatePasswordReset( 38 | $email, 39 | AccountManagement::EMAIL_RESET 40 | ); 41 | } catch (NoSuchEntityException $exception) { 42 | // Do nothing, we don't want anyone to use this action to determine which email accounts are registered. 43 | } catch (SecurityViolationException $exception) { 44 | $this->messageManager->addErrorMessage($exception->getMessage()); 45 | return $resultRedirect->setPath('*/*/forgotpassword'); 46 | } catch (\Exception $exception) { 47 | $this->messageManager->addExceptionMessage( 48 | $exception, 49 | __('We\'re unable to send the password reset email.') 50 | ); 51 | return $resultRedirect->setPath('*/*/forgotpassword'); 52 | } 53 | $this->messageManager->addSuccessMessage($this->getSuccessMessage($email)); 54 | return $resultRedirect->setPath('*/*/'); 55 | } else { 56 | $this->messageManager->addErrorMessage(__('Please enter your email.')); 57 | return $resultRedirect->setPath('*/*/forgotpassword'); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /view/frontend/web/template/form/element/email.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 |
15 |
16 |
17 | 20 |
21 | 29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 | 40 |
41 | 47 | 48 |
49 | 50 |
51 | 52 | 53 | 54 |
55 | 56 |
57 | 58 |
59 |
60 | 61 | 62 | 63 |
64 |
65 |
66 | 67 |
68 |
69 | 70 | -------------------------------------------------------------------------------- /Model/Event/ChangeEavAttribute.php: -------------------------------------------------------------------------------- 1 | config = $config; 45 | $this->attributeFactory = $attributeFactory; 46 | } 47 | 48 | /** 49 | * Change the attribute of username after the configuration 50 | * has been changed 51 | * 52 | * Event: admin_system_config_changed_section_username 53 | * 54 | * @param \Magento\Framework\Event\Observer $observer Observer 55 | * @throws \Exception 56 | */ 57 | public function execute(\Magento\Framework\Event\Observer $observer) 58 | { 59 | $minLength = $this->config->getValue('username/general/min_length'); 60 | $maxLength = $this->config->getValue('username/general/max_length'); 61 | $inputValidation = $this->config->getValue('username/general/input_validation'); 62 | 63 | if ($minLength > $maxLength) { 64 | throw new \Exception ( 65 | __('Sorry but you cannot set a minimum length value %s bigger than the maximum length value %s. Please, change the values.', 66 | $minLength, 67 | $maxLength) 68 | ); 69 | } 70 | 71 | /* @var $attributeUsernameModel \Magento\Customer\Model\Attribute */ 72 | $attributeUsernameModel = $this->attributeFactory->create(); 73 | $attributeUsernameModel->loadByCode('customer', 'username'); 74 | 75 | if ($attributeUsernameModel->getId()) { 76 | $rules = $attributeUsernameModel->getValidateRules(); 77 | $rules['max_text_length'] = $maxLength; 78 | $rules['min_text_length'] = $minLength; 79 | 80 | if ($inputValidation != 'default' && $inputValidation != 'custom') { 81 | $rules['input_validation'] = $inputValidation; 82 | } else { 83 | $rules['input_validation'] = ''; // validation is done at save level of the customer model 84 | } 85 | 86 | $usedInGrid = $this->config->getValue('username/general/grid'); 87 | $attributeUsernameModel->setData('is_used_in_grid', $usedInGrid); 88 | 89 | $attributeUsernameModel->setValidateRules($rules); 90 | $attributeUsernameModel->save(); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /view/frontend/templates/form/login.phtml: -------------------------------------------------------------------------------- 1 | 11 | helper('\Diglin\Username\Helper\Customer')->isEnabled()) { 24 | $usernameLabel = __('Email/Username'); 25 | $usernameInputType = 'text'; 26 | $usernameInputValidation = ""; 27 | } 28 | 29 | ?> 30 |
31 |
32 | 33 |
34 |
35 | 62 |
63 |
64 | -------------------------------------------------------------------------------- /Test/Helper/CustomerTest.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Test\Helper; 12 | 13 | /** 14 | * Class CustomerTest 15 | * @package Diglin\Username\Test\Helper 16 | */ 17 | class CustomerTest extends \PHPUnit_Framework_TestCase 18 | { 19 | /** 20 | * @var array 21 | */ 22 | private static $flattenedFixture = [ 23 | 'configData1' => [ 24 | 'input_validation' => 'default', 25 | 'custom_validation' => '', 26 | 'min_length' => '6', 27 | 'max_length' => '30' 28 | ], 29 | 'configData2' => [ 30 | 'input_validation' => 'default', 31 | 'custom_validation' => '', 32 | 'min_length' => '3', 33 | 'max_length' => '50' 34 | ], 35 | 'configData3' => [ 36 | 'input_validation' => 'alpha', 37 | 'custom_validation' => '', 38 | 'min_length' => '6', 39 | 'max_length' => '30' 40 | ], 41 | 'configData4' => [ 42 | 'input_validation' => 'numeric', 43 | 'custom_validation' => '', 44 | 'min_length' => '6', 45 | 'max_length' => '30' 46 | ], 47 | 'configData5' => [ 48 | 'input_validation' => 'alphanumeric', 49 | 'custom_validation' => '', 50 | 'min_length' => '6', 51 | 'max_length' => '30' 52 | ], 53 | 'configData6' => [ 54 | 'input_validation' => 'custom', 55 | 'custom_validation' => '^[\d]{4}\-[\d]{4}\-[\w]{4}$', 56 | 'min_length' => '6', 57 | 'max_length' => '30' 58 | ], 59 | ]; 60 | 61 | public function testGenerateCustomer() 62 | { 63 | foreach (self::$flattenedFixture as $config) { 64 | $inputValidation = $config['input_validation']; 65 | $minLength = $config['min_length']; 66 | $maxLength = $config['max_length']; 67 | $customValidation = $config['custom_validation']; 68 | 69 | switch ($inputValidation) { 70 | case 'alpha': // letters 71 | $regex = '^[a-zA-Z]{%d,%d}$'; 72 | break; 73 | case 'numeric': // digits 74 | $regex = '^[\d]{%d,%d}$'; 75 | break; 76 | case 'alphanumeric': // letters & digits 77 | $regex = '^[\d\w]{%d,%d}$'; 78 | break; 79 | case 'custom': 80 | $regex = $customValidation; 81 | break; 82 | case 'default': // letters, digits and _- characters 83 | default: 84 | $regex = '^[\w]{%d,%d}$'; 85 | break; 86 | } 87 | 88 | $regex = sprintf($regex, $minLength, $maxLength); 89 | 90 | // 1. Read the grammar. 91 | $grammar = new \Hoa\File\Read('hoa://Library/Regex/Grammar.pp'); 92 | 93 | // 2. Load the compiler. 94 | $compiler = \Hoa\Compiler\Llk\Llk::load($grammar); 95 | 96 | // 3. Lex, parse and produce the AST. 97 | $ast = $compiler->parse($regex); 98 | 99 | $generator = new \Hoa\Regex\Visitor\Isotropic(new \Hoa\Math\Sampler\Random()); 100 | $username = $generator->visit($ast); 101 | 102 | echo sprintf('Username %s with the following regex has been tested %s', $username, $regex) . PHP_EOL; 103 | 104 | $this->assertRegExp('@'.$regex.'@', $username, 'Username does not comply to the regex ' . $regex); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /view/adminhtml/templates/config/generate.phtml: -------------------------------------------------------------------------------- 1 | 8 | * @copyright Copyright (c) 2008-2015 Diglin GmbH - Switzerland (http://www.diglin.com) 9 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) 10 | */ 11 | use Diglin\Username\Model\Generate\Flag; 12 | 13 | /* @var $block Diglin\Username\Block\Config\Form\Field\Generate.php */ 14 | ?> 15 | 95 | 96 | getButtonHtml(); ?><?php echo __('Generate') ?> 97 | -------------------------------------------------------------------------------- /Setup/InstallSchema.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Training\CustomerComment\Setup 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Setup; 12 | 13 | use Magento\Customer\Model\Customer; 14 | use Magento\Eav\Model\Config; 15 | use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory; 16 | use Magento\Eav\Setup\EavSetup; 17 | use Magento\Framework\Setup\ModuleContextInterface; 18 | use Magento\Framework\Setup\SchemaSetupInterface; 19 | use Magento\Framework\Setup\InstallSchemaInterface; 20 | 21 | /** 22 | * @codeCoverageIgnore 23 | */ 24 | class InstallSchema implements InstallSchemaInterface 25 | { 26 | /** 27 | * @var Config 28 | */ 29 | private $eavConfig; 30 | /** 31 | * @var AttributeSetFactory 32 | */ 33 | private $attributeSet; 34 | /** 35 | * @var EavSetup 36 | */ 37 | private $eavSetup; 38 | 39 | /** 40 | * InstallSchema constructor. 41 | */ 42 | public function __construct( 43 | AttributeSetFactory $attributeSet, 44 | Config $eavConfig, 45 | EavSetup $eavSetup 46 | ) 47 | { 48 | $this->attributeSet = $attributeSet; 49 | $this->eavConfig = $eavConfig; 50 | $this->eavSetup = $eavSetup; 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength) 56 | */ 57 | public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) 58 | { 59 | $setup->startSetup(); 60 | 61 | $entityType = $this->eavConfig->getEntityType(Customer::ENTITY); 62 | $attributeSet = $this->attributeSet->create(); 63 | $groupId = $attributeSet->getDefaultGroupId($entityType->getDefaultAttributeSetId()); 64 | 65 | $this->eavSetup->addAttribute(Customer::ENTITY, 'username', 66 | [ 67 | 'label' => 'Username', 68 | 'input' => 'text', 69 | 'required' => 0, 70 | 'user_defined' => 1, 71 | 'unique' => 0, 72 | 'system' => 0, 73 | 'group' => $groupId, 74 | 'is_used_in_grid' => 1, 75 | 'is_visible_in_grid' => 1, 76 | 'is_filterable_in_grid' => 1, 77 | 'is_searchable_in_grid' => 1, 78 | 'validate_rules' => serialize([ 79 | 'max_text_length' => 30, 80 | 'min_text_length' => 6 81 | ]) 82 | ] 83 | ); 84 | 85 | $setup->getConnection() 86 | ->addColumn( 87 | $setup->getTable('customer_grid_flat'), 88 | 'username', 89 | [ 90 | 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 91 | 'default' => '', 92 | 'comment' => 'Customer Username' 93 | ] 94 | ); 95 | 96 | $setup->getConnection() 97 | ->addColumn( 98 | $setup->getTable('quote'), 'customer_username', 99 | [ 100 | 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 101 | 'length' => '255', 102 | 'nullable' => true, 103 | 'comment' => 'Customer Username', 104 | 'after' => 'customer_taxvat' 105 | ] 106 | ); 107 | 108 | $setup->getConnection() 109 | ->addColumn( 110 | $setup->getTable('sales_order'), 'customer_username', 111 | [ 112 | 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 113 | 'length' => '255', 114 | 'nullable' => true, 115 | 'comment' => 'Customer Username', 116 | 'after' => 'customer_taxvat' 117 | ] 118 | ); 119 | 120 | $setup->endSetup(); 121 | } 122 | } -------------------------------------------------------------------------------- /Block/Widget/Username.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Block\Widget; 12 | 13 | use Diglin\Username\Helper\Customer; 14 | use Magento\Customer\Api\CustomerMetadataInterface; 15 | use Magento\Customer\Api\CustomerRepositoryInterface; 16 | use Magento\Customer\Api\Data\CustomerInterface; 17 | use Magento\Customer\Block\Widget\AbstractWidget; 18 | 19 | /** 20 | * Class Username 21 | * 22 | * @method CustomerInterface getObject() 23 | * @method Username setObject(CustomerInterface $customer) 24 | * 25 | * @package Diglin\Username\Block\Widget 26 | */ 27 | class Username extends AbstractWidget 28 | { 29 | /** 30 | * @var \Magento\Customer\Model\Session 31 | */ 32 | protected $_customerSession; 33 | 34 | /** 35 | * @var CustomerRepositoryInterface 36 | */ 37 | protected $customerRepository; 38 | /** 39 | * @var Customer 40 | */ 41 | private $usernameHelper; 42 | 43 | 44 | /** 45 | * Create an instance of the Username widget 46 | * 47 | * @param \Magento\Framework\View\Element\Template\Context $context 48 | * @param \Magento\Customer\Helper\Address $addressHelper 49 | * @param CustomerMetadataInterface $customerMetadata 50 | * @param CustomerRepositoryInterface $customerRepository 51 | * @param \Magento\Customer\Model\Session $customerSession 52 | * @param Customer $usernameHelper 53 | * @param array $data 54 | */ 55 | public function __construct( 56 | \Magento\Framework\View\Element\Template\Context $context, 57 | \Magento\Customer\Helper\Address $addressHelper, 58 | CustomerMetadataInterface $customerMetadata, 59 | CustomerRepositoryInterface $customerRepository, 60 | \Magento\Customer\Model\Session $customerSession, 61 | Customer $usernameHelper, 62 | array $data = [] 63 | ) { 64 | $this->_customerSession = $customerSession; 65 | $this->customerRepository = $customerRepository; 66 | parent::__construct($context, $addressHelper, $customerMetadata, $data); 67 | $this->_isScopePrivate = true; 68 | $this->usernameHelper = $usernameHelper; 69 | } 70 | 71 | /** 72 | * Initialize block 73 | * 74 | * @return void 75 | */ 76 | public function _construct() 77 | { 78 | parent::_construct(); 79 | $this->setTemplate('widget/username.phtml'); 80 | } 81 | 82 | /** 83 | * Check if username attribute enabled in system 84 | * @return bool 85 | */ 86 | public function isEnabled() 87 | { 88 | return $this->usernameHelper->isEnabled() && ($this->_getAttribute('username') ? (bool)$this->_getAttribute('username')->isVisible() : false); 89 | } 90 | 91 | /** 92 | * Check if username attribute marked as required 93 | * @return bool 94 | */ 95 | public function isRequired() 96 | { 97 | return $this->_getAttribute('username') ? (bool)$this->_getAttribute('username')->isRequired() : false; 98 | } 99 | 100 | /** 101 | * Get current customer from session 102 | * 103 | * @return CustomerInterface 104 | */ 105 | public function getCustomer() 106 | { 107 | return $this->customerRepository->getById($this->_customerSession->getCustomerId()); 108 | } 109 | 110 | /** 111 | * @return bool 112 | */ 113 | public function isEditable() 114 | { 115 | return $this->usernameHelper->isEditableOnFrontend() || $this->getData('is_editable'); 116 | } 117 | 118 | /** 119 | * @return mixed 120 | */ 121 | public function getUsername() 122 | { 123 | if (!$this->getData('username')) { 124 | if ($this->getObject()->getCustomAttribute('username') instanceof \Magento\Framework\Api\AttributeInterface) { 125 | $this->setData('username', $this->getObject()->getCustomAttribute('username')->getValue()); 126 | } 127 | } 128 | 129 | return $this->getData('username'); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /view/frontend/web/template/authentication.html: -------------------------------------------------------------------------------- 1 | 7 |
8 | 14 | 90 |
91 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Sync/Generate.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Controller\Adminhtml\Sync; 12 | 13 | use Diglin\Username\Controller\Adminhtml\Sync; 14 | use Diglin\Username\Model\Generate\Flag; 15 | use Magento\Backend\App\Action\Context; 16 | use Magento\Framework\App\Config as AppConfig; 17 | use Magento\Eav\Model\Config; 18 | use Magento\Framework\App\ResourceConnection; 19 | use Magento\Framework\DB\LoggerInterface; 20 | use Diglin\Username\Helper\Customer as CustomerHelper; 21 | 22 | /** 23 | * Class Generate 24 | * @package Diglin\Username\Controller\Adminhtml\Username\Sync 25 | */ 26 | class Generate extends Sync 27 | { 28 | /** 29 | * @var LoggerInterface 30 | */ 31 | private $logger; 32 | /** 33 | * @var Config 34 | */ 35 | private $eavConfig; 36 | 37 | /** 38 | * @var \Magento\Framework\DB\Adapter\AdapterInterface 39 | */ 40 | private $connection; 41 | 42 | /** 43 | * @var ResourceConnection 44 | */ 45 | private $resource; 46 | 47 | /** 48 | * @var AppConfig 49 | */ 50 | private $config; 51 | 52 | /** 53 | * @var CustomerHelper 54 | */ 55 | private $helper; 56 | 57 | public function __construct( 58 | Context $context, 59 | LoggerInterface $logger, 60 | Config $eavConfig, 61 | ResourceConnection $resource, 62 | AppConfig $config, 63 | CustomerHelper $helper 64 | ) 65 | { 66 | parent::__construct($context); 67 | 68 | $this->logger = $logger; 69 | $this->eavConfig = $eavConfig; 70 | $this->config = $config; 71 | $this->resource = $resource; 72 | $this->connection = $resource->getConnection('core_read'); 73 | $this->helper = $helper; 74 | } 75 | 76 | public function execute() 77 | { 78 | session_write_close(); 79 | 80 | $flag = $this->_getSyncFlag(); 81 | $flag 82 | ->setState(Flag::STATE_RUNNING) 83 | ->save(); 84 | 85 | $flag->setFlagData(array()); 86 | 87 | try { 88 | $usernameAttribute = $this->eavConfig->getAttribute('customer', 'username'); 89 | 90 | /** 91 | * Get customer entity_ids having a username 92 | */ 93 | $select = $this->connection 94 | ->select() 95 | ->from($this->resource->getTableName('customer_entity_varchar'), 'entity_id') 96 | ->where('attribute_id = ?', $usernameAttribute->getId()) 97 | ->where('value IS NOT NULL'); 98 | 99 | $ids = $this->connection->fetchCol($select); 100 | 101 | /** 102 | * Get additional data from customers who doesn't have a username 103 | */ 104 | $select = $this->connection 105 | ->select() 106 | ->from(array('c' => $this->resource->getTableName('customer_entity')), array('email', 'entity_id')) 107 | ->group('c.entity_id'); 108 | 109 | if (!empty($ids)) { 110 | $select->where('c.entity_id NOT IN (' . implode(',', $ids) . ')'); 111 | } 112 | 113 | // @todo - add support for Customer Website Share option (check that the username doesn't already exist in other websites) 114 | 115 | // Create username for old customers to prevent problem when creating an order as a guest 116 | $customers = $this->connection->fetchAll($select); 117 | $totalItemsDone = 0; 118 | 119 | $flagData['total_items'] = count($customers); 120 | 121 | $flag 122 | ->setFlagData($flagData) 123 | ->save(); 124 | 125 | foreach ($customers as $customer) { 126 | 127 | $customer['value'] = $this->helper->generateUsername(); 128 | $customer['attribute_id'] = $usernameAttribute->getId(); 129 | 130 | unset($customer['email']); 131 | unset($customer['value_id']); 132 | 133 | $this->connection->insert($this->connection->getTableName('customer_entity_varchar'), $customer); 134 | 135 | $flagData['total_items_done'] = $totalItemsDone; 136 | $flag 137 | ->setFlagData($flagData) 138 | ->save(); 139 | } 140 | 141 | } catch (\Exception $e) { 142 | $this->logger->critical($e); 143 | $flag->setHasErrors(true); 144 | } 145 | $flag->setState(Flag::STATE_FINISHED)->save(); 146 | } 147 | } -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 |
15 | separator-top 16 | 17 | customer 18 | Diglin_Username::config_username 19 | 20 | 21 | 22 | 23 | Magento\Config\Model\Config\Source\Yesno 24 | 25 | 26 | 27 | 28 | Magento\Config\Model\Config\Source\Yesno 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Diglin\Username\Model\Config\Source\Inputvalidation 45 | 46 | 47 | 48 | 49 | 50 | /^[\w-]*$/. More info at PHP Manual]]> 51 | 52 | custom 53 | 54 | 55 | 56 | 57 | 58 | ]]> 59 | 60 | custom 61 | 62 | 63 | 64 | 65 | 66 | Magento\Config\Model\Config\Source\Yesno 67 | 68 | 69 | 70 | 71 | 72 | 73 | Diglin\Username\Block\Config\Form\Field\Generate 74 | 75 | 76 |
77 |
78 |
79 | -------------------------------------------------------------------------------- /view/frontend/web/js/view/form/element/email.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2016 Magento. All rights reserved. 3 | * See COPYING.txt for license details. 4 | */ 5 | /*browser:true*/ 6 | /*global define*/ 7 | define([ 8 | 'jquery', 9 | 'uiComponent', 10 | 'ko', 11 | 'Magento_Customer/js/model/customer', 12 | 'Magento_Customer/js/action/check-email-availability', 13 | 'Magento_Customer/js/action/login', 14 | 'Magento_Checkout/js/model/quote', 15 | 'Magento_Checkout/js/checkout-data', 16 | 'Magento_Checkout/js/model/full-screen-loader', 17 | 'mage/validation' 18 | ], function ($, Component, ko, customer, checkEmailAvailability, loginAction, quote, checkoutData, fullScreenLoader) { 19 | 'use strict'; 20 | 21 | var validatedEmail = checkoutData.getValidatedEmailValue(); 22 | 23 | if (validatedEmail && !customer.isLoggedIn()) { 24 | quote.guestEmail = validatedEmail; 25 | } 26 | 27 | return Component.extend({ 28 | defaults: { 29 | template: 'Diglin_Username/form/element/email', 30 | email: checkoutData.getInputFieldEmailValue(), 31 | emailFocused: false, 32 | isLoading: false, 33 | isPasswordVisible: false, 34 | listens: { 35 | email: 'emailHasChanged', 36 | emailFocused: 'validateEmail' 37 | } 38 | }, 39 | checkDelay: 2000, 40 | checkRequest: null, 41 | isEmailCheckComplete: null, 42 | isCustomerLoggedIn: customer.isLoggedIn, 43 | forgotPasswordUrl: window.checkoutConfig.forgotPasswordUrl, 44 | emailCheckTimeout: 0, 45 | 46 | /** 47 | * Initializes observable properties of instance 48 | * 49 | * @returns {Object} Chainable. 50 | */ 51 | initObservable: function () { 52 | this._super() 53 | .observe(['email', 'emailFocused', 'isLoading', 'isPasswordVisible']); 54 | 55 | return this; 56 | }, 57 | 58 | /** 59 | * Callback on changing email property 60 | */ 61 | emailHasChanged: function () { 62 | var self = this; 63 | 64 | clearTimeout(this.emailCheckTimeout); 65 | 66 | if (self.validateEmail()) { 67 | quote.guestEmail = self.email(); 68 | checkoutData.setValidatedEmailValue(self.email()); 69 | } 70 | this.emailCheckTimeout = setTimeout(function () { 71 | if (self.validateEmail()) { 72 | self.checkEmailAvailability(); 73 | } else { 74 | self.isPasswordVisible(false); 75 | } 76 | }, self.checkDelay); 77 | 78 | checkoutData.setInputFieldEmailValue(self.email()); 79 | }, 80 | 81 | /** 82 | * Check email existing. 83 | */ 84 | checkEmailAvailability: function () { 85 | var self = this; 86 | this.validateRequest(); 87 | this.isEmailCheckComplete = $.Deferred(); 88 | this.isLoading(true); 89 | this.checkRequest = checkEmailAvailability(this.isEmailCheckComplete, this.email()); 90 | 91 | $.when(this.isEmailCheckComplete).done(function () { 92 | self.isPasswordVisible(false); 93 | }).fail(function () { 94 | self.isPasswordVisible(true); 95 | }).always(function () { 96 | self.isLoading(false); 97 | }); 98 | }, 99 | 100 | /** 101 | * If request has been sent -> abort it. 102 | * ReadyStates for request aborting: 103 | * 1 - The request has been set up 104 | * 2 - The request has been sent 105 | * 3 - The request is in process 106 | */ 107 | validateRequest: function () { 108 | if (this.checkRequest != null && $.inArray(this.checkRequest.readyState, [1, 2, 3])) { 109 | this.checkRequest.abort(); 110 | this.checkRequest = null; 111 | } 112 | }, 113 | 114 | /** 115 | * Local email validation. 116 | * 117 | * @param {Boolean} focused - input focus. 118 | * @returns {Boolean} - validation result. 119 | */ 120 | validateEmail: function (focused) { 121 | var loginFormSelector = 'form[data-role=email-with-possible-login]', 122 | usernameSelector = loginFormSelector + ' input[name=username]', 123 | loginForm = $(loginFormSelector), 124 | validator; 125 | 126 | loginForm.validation(); 127 | 128 | if (focused === false && !!this.email()) { 129 | return !!$(usernameSelector).valid(); 130 | } 131 | 132 | validator = loginForm.validate(); 133 | 134 | return validator.check(usernameSelector); 135 | }, 136 | 137 | /** 138 | * Log in form submitting callback. 139 | * 140 | * @param {HTMLElement} loginForm - form element. 141 | */ 142 | login: function (loginForm) { 143 | var loginData = {}, 144 | formDataArray = $(loginForm).serializeArray(); 145 | 146 | formDataArray.forEach(function (entry) { 147 | loginData[entry.name] = entry.value; 148 | }); 149 | 150 | if (this.isPasswordVisible() && $(loginForm).validation() && $(loginForm).validation('isValid')) { 151 | fullScreenLoader.startLoader(); 152 | loginAction(loginData).always(function() { 153 | fullScreenLoader.stopLoader(); 154 | }); 155 | } 156 | } 157 | }); 158 | }); 159 | -------------------------------------------------------------------------------- /Helper/Customer.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Helper; 12 | 13 | use Magento\Framework\App\Config; 14 | use Magento\Customer\Model\ResourceModel\CustomerRepository; 15 | use Magento\Framework\Api\SearchCriteriaBuilder; 16 | use Magento\Framework\App\Helper\Context; 17 | 18 | /** 19 | * Class Customer 20 | * @package Diglin\Username\Helper 21 | */ 22 | class Customer extends \Magento\Framework\App\Helper\AbstractHelper 23 | { 24 | const CFG_ENABLED = 'username/general/enabled'; 25 | const CFG_FRONTEND = 'username/general/frontend'; 26 | const CFG_INPUT_VALIDATION = 'username/general/input_validation'; 27 | const CFG_CASE_SENSITIVE = 'username/general/case_sensitive'; 28 | const CFG_INPUT_VALIDATION_CUSTOM = 'username/general/input_validation_custom'; 29 | const CFG_INPUT_VALIDATION_CUSTOM_MESSAGE = 'username/general/input_validation_custom_message'; 30 | const CFG_INPUT_MAXLENGTH = 'username/general/max_length'; 31 | const CFG_INPUT_MINLENGTH = 'username/general/min_length'; 32 | 33 | /** 34 | * @var CustomerRepository 35 | */ 36 | private $customerRepository; 37 | /** 38 | * @var SearchCriteriaBuilder 39 | */ 40 | private $searchCriteriaBuilder; 41 | /** 42 | * @var Config 43 | */ 44 | private $config; 45 | 46 | /** 47 | * Customer constructor. 48 | * @param Context $context 49 | * @param CustomerRepository $customerRepository 50 | * @param SearchCriteriaBuilder $searchCriteriaBuilder 51 | */ 52 | public function __construct( 53 | Context $context, 54 | CustomerRepository $customerRepository, 55 | SearchCriteriaBuilder $searchCriteriaBuilder, 56 | Config $config 57 | ){ 58 | $this->customerRepository = $customerRepository; 59 | 60 | parent::__construct($context); 61 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 62 | $this->config = $config; 63 | } 64 | 65 | /** 66 | * @param $username 67 | * @param null $websiteId 68 | * @return bool|\Magento\Customer\Api\Data\CustomerInterface 69 | */ 70 | public function customerUsernameExists($username, $websiteId = null) 71 | { 72 | return $this->loadByUsername($username, $websiteId); 73 | } 74 | 75 | /** 76 | * @param $username 77 | * @param null $websiteId 78 | * @return bool|\Magento\Customer\Api\Data\CustomerInterface 79 | */ 80 | public function loadByUsername($username, $websiteId = null) 81 | { 82 | $this->searchCriteriaBuilder->addFilter('username', $username, 'like'); 83 | 84 | if (!is_null($websiteId)) { 85 | $this->searchCriteriaBuilder->addFilter('website_id', $websiteId, 'eq'); 86 | } 87 | 88 | $searchCriteria = $this->searchCriteriaBuilder->create(); 89 | $list = $this->customerRepository->getList($searchCriteria); 90 | 91 | if ($list->getTotalCount() > 0) { 92 | foreach ($list->getItems() as $item) { 93 | 94 | if ($this->isCaseSensitive() && $username != $item->getCustomAttribute('username')->getValue()) { 95 | return false; 96 | } 97 | 98 | return $item; 99 | } 100 | } 101 | 102 | return false; 103 | } 104 | 105 | /** 106 | * Is Username editable on frontend 107 | * 108 | * @return bool 109 | */ 110 | public function isEditableOnFrontend() 111 | { 112 | return $this->config->isSetFlag(self::CFG_FRONTEND); 113 | } 114 | 115 | /** 116 | * @return bool 117 | */ 118 | public function isEnabled() 119 | { 120 | return $this->config->isSetFlag(self::CFG_ENABLED); 121 | } 122 | 123 | /** 124 | * @return bool 125 | */ 126 | public function isCaseSensitive() 127 | { 128 | return $this->config->isSetFlag(self::CFG_CASE_SENSITIVE); 129 | } 130 | 131 | /** 132 | * @return mixed 133 | * @throws \Hoa\Compiler\Exception 134 | * @throws \Hoa\Compiler\Exception\UnexpectedToken 135 | * @throws \Hoa\Regex\Exception 136 | */ 137 | public function generateUsername() 138 | { 139 | $inputValidation = $this->config->getValue(self::CFG_INPUT_VALIDATION); 140 | $customValidation = $this->config->getValue(self::CFG_INPUT_VALIDATION_CUSTOM); 141 | $maxLength = (int) $this->config->getValue(self::CFG_INPUT_MAXLENGTH); 142 | $minLength = (int) $this->config->getValue(self::CFG_INPUT_MINLENGTH); 143 | 144 | switch ($inputValidation) { 145 | case 'alpha': // letters 146 | $regex = '^[a-zA-Z]{%d,%d}$'; 147 | break; 148 | case 'numeric': // digits 149 | $regex = '^[\d]{%d,%d}$'; 150 | break; 151 | case 'alphanumeric': // letters & digits 152 | $regex = '^[\d\w]{%d,%d}$'; 153 | break; 154 | case 'custom': 155 | 156 | // Remove potential delimiter for Hoa\Regex class 157 | $delimiter = substr($customValidation, 0, 1); 158 | $endDelimiter = -1; 159 | if ($delimiter != substr($customValidation, $endDelimiter)) { 160 | $endDelimiter = -2; 161 | } 162 | 163 | if ($delimiter == substr($customValidation, $endDelimiter)) { 164 | $regex = substr($customValidation, 1, $endDelimiter); 165 | } else { 166 | $regex = $customValidation; 167 | } 168 | 169 | break; 170 | case 'default': // letters, digits and _- characters 171 | default: 172 | $regex = '^[\w]{%d,%d}$'; 173 | break; 174 | } 175 | 176 | $regex = sprintf($regex, $minLength, $maxLength); 177 | 178 | // 1. Read the grammar. 179 | $grammar = new \Hoa\File\Read('hoa://Library/Regex/Grammar.pp'); 180 | 181 | // 2. Load the compiler. 182 | $compiler = \Hoa\Compiler\Llk\Llk::load($grammar); 183 | 184 | // 3. Lex, parse and produce the AST. 185 | $ast = $compiler->parse($regex); 186 | 187 | $generator = new \Hoa\Regex\Visitor\Isotropic(new \Hoa\Math\Sampler\Random()); 188 | $username = $generator->visit($ast); 189 | 190 | if (!$this->isCaseSensitive()) { 191 | $username = strtolower($username); 192 | } 193 | 194 | if ($this->customerUsernameExists($username)) { 195 | $username = $this->generateUsername(); 196 | } 197 | 198 | return $username; 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /view/frontend/templates/form/edit.phtml: -------------------------------------------------------------------------------- 1 | 11 |
12 |
13 | getBlockHtml('formkey')?> 14 |
15 | getLayout()->createBlock('Diglin\Username\Block\Widget\Username') ?> 16 | isEnabled()): ?> 17 | setObject($block->getCustomer()) 19 | ->toHtml() ?> 20 | 21 | 22 | getLayout()->createBlock('Magento\Customer\Block\Widget\Name')->setObject($block->getCustomer())->toHtml() ?> 23 | 24 | getLayout()->createBlock('Magento\Customer\Block\Widget\Dob') ?> 25 | getLayout()->createBlock('Magento\Customer\Block\Widget\Taxvat') ?> 26 | getLayout()->createBlock('Magento\Customer\Block\Widget\Gender') ?> 27 | isEnabled()): ?> 28 | setDate($block->getCustomer()->getDob())->toHtml() ?> 29 | 30 | isEnabled()): ?> 31 | setTaxvat($block->getCustomer()->getTaxvat())->toHtml() ?> 32 | 33 | isEnabled()): ?> 34 | setGender($block->getCustomer()->getGender())->toHtml() ?> 35 | 36 |
37 | 38 | 39 |
40 |
41 | getChangePassword()): ?> checked="checked" class="checkbox" /> 42 | 43 |
44 |
45 | 46 |
47 |
48 |
49 | 50 |
51 | 52 |
53 |
54 | 60 |
61 | 62 |
63 | 69 |
70 |

 

71 |
72 |
73 |
74 |
75 | 76 |
77 | 80 |
81 |
82 | getChildHtml('form_additional_info'); ?> 83 |
84 |
85 |
86 | 87 |
88 |
89 | 90 |
91 |
92 |
93 | 123 | 134 | -------------------------------------------------------------------------------- /Plugin/Model/ResourceModel/CustomerRepositoryPlugin.php: -------------------------------------------------------------------------------- 1 | 6 | * @category Diglin 7 | * @package Diglin_ 8 | * @copyright Copyright (c) 2011-2016 Diglin (http://www.diglin.com) 9 | */ 10 | 11 | namespace Diglin\Username\Plugin\Model\ResourceModel; 12 | 13 | use Diglin\Username\Helper\Customer as CustomerHelper; 14 | use Diglin\Username\Helper\Customer; 15 | use Magento\Checkout\Helper\Data; 16 | use Magento\Config\Model\Config\Backend\Admin\Custom; 17 | use Magento\Customer\Model\Metadata\CustomerMetadata; 18 | use Magento\Framework\Api\SearchCriteriaBuilder; 19 | use Magento\Framework\App\Config; 20 | use Magento\Framework\App\State; 21 | use Magento\Framework\Exception\InputException; 22 | use Magento\Framework\Exception\NoSuchEntityException; 23 | use Magento\Framework\ObjectManagerInterface; 24 | 25 | /** 26 | * Class CustomerRepositoryPlugin 27 | * @package Diglin\Username\Plugin\Model\ResourceModel 28 | */ 29 | class CustomerRepositoryPlugin 30 | { 31 | /** 32 | * @var SearchCriteriaBuilder 33 | */ 34 | private $searchCriteriaBuilder; 35 | /** 36 | * @var CustomerMetadata 37 | */ 38 | private $customerMetadata; 39 | /** 40 | * @var Config 41 | */ 42 | private $config; 43 | /** 44 | * @var State 45 | */ 46 | private $state; 47 | /** 48 | * @var CustomerHelper 49 | */ 50 | private $customerHelper; 51 | /** 52 | * @var Data 53 | */ 54 | private $checkoutHelper; 55 | /** 56 | * @var ObjectManagerInterface 57 | */ 58 | private $objectManager; 59 | 60 | /** 61 | * CustomerRepositoryPlugin constructor. 62 | * @param SearchCriteriaBuilder $searchCriteriaBuilder 63 | * @param CustomerMetadata $customerMetadata 64 | * @param Config $config 65 | * @param State $state 66 | * @param CustomerHelper $customerHelper 67 | * @param Data $checkoutHelper 68 | * @param ObjectManagerInterface $objectManager 69 | */ 70 | public function __construct( 71 | SearchCriteriaBuilder $searchCriteriaBuilder, 72 | CustomerMetadata $customerMetadata, 73 | Config $config, 74 | State $state, 75 | CustomerHelper $customerHelper, 76 | Data $checkoutHelper, 77 | ObjectManagerInterface $objectManager 78 | ) 79 | { 80 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 81 | $this->customerMetadata = $customerMetadata; 82 | $this->config = $config; 83 | $this->state = $state; 84 | $this->customerHelper = $customerHelper; 85 | $this->checkoutHelper = $checkoutHelper; 86 | $this->objectManager = $objectManager; 87 | } 88 | 89 | /** 90 | * @param \Magento\Customer\Model\ResourceModel\CustomerRepository $subject 91 | * @param $username 92 | * @param null $websiteId 93 | * @return array 94 | */ 95 | public function beforeGet(\Magento\Customer\Model\ResourceModel\CustomerRepository $subject, $username, $websiteId = null) 96 | { 97 | if (strpos($username, '@') === false) { 98 | $customerFound = $this->customerHelper->loadByUsername($username, $websiteId); 99 | if ($customerFound) { 100 | $username = $customerFound->getEmail(); 101 | } 102 | } 103 | 104 | return [$username, $websiteId]; 105 | } 106 | 107 | /** 108 | * @param \Magento\Customer\Model\ResourceModel\CustomerRepository $subject 109 | * @param \Magento\Customer\Api\Data\CustomerInterface $customer 110 | * @param null $passwordHash 111 | * @return array 112 | * @throws InputException 113 | * @throws \Magento\Framework\Exception\LocalizedException 114 | */ 115 | public function beforeSave(\Magento\Customer\Model\ResourceModel\CustomerRepository $subject, \Magento\Customer\Api\Data\CustomerInterface $customer, $passwordHash = null) 116 | { 117 | $exception = new InputException(); 118 | $customerDataOriginal = $usernameOriginal = null; 119 | 120 | $usernameAttribute = $customer->getCustomAttribute('username'); 121 | 122 | if (is_null($usernameAttribute)) { 123 | return [$customer, $passwordHash]; 124 | } 125 | 126 | $username = $usernameAttribute->getValue(); 127 | 128 | if ($customer->getId()) { 129 | $customerDataOriginal = $subject->getById($customer->getId()); 130 | $originalUsernameAttribute = $customerDataOriginal->getCustomAttribute('username'); 131 | if ($originalUsernameAttribute) { 132 | $usernameOriginal = $originalUsernameAttribute->getValue(); 133 | } 134 | } 135 | 136 | if (!is_null($usernameOriginal) && $usernameOriginal != $username) { 137 | 138 | // @todo return true even in none checkout process which is not expected 139 | // $guestMethod = $this->checkoutHelper->isAllowedGuestCheckout($this->checkoutHelper->getQuote()); 140 | $guestMethod = false; 141 | 142 | /** 143 | * Validate Username 144 | * - No duplicate must exist 145 | * - Must respect format of the username 146 | * - check if required or not 147 | * - Do not allow frontend edition if configuration is enabled 148 | * - Do not check for guest 149 | */ 150 | 151 | if ($this->state->getAreaCode() == 'frontend' && !$this->customerHelper->isEditableOnFrontend()) { 152 | $exception->addError(__('Username cannot be edited on frontend.')); 153 | $customer->setCustomAttribute('username', $customerDataOriginal->getCustomAttribute('username')->getValue()); 154 | } else if ($guestMethod != \Magento\Checkout\Model\Type\Onepage::METHOD_GUEST) { 155 | $this->validate($customer, $exception); 156 | } 157 | } else if (!$customer->getId()) { 158 | $this->validate($customer, $exception); 159 | } 160 | 161 | if ($exception->wasErrorAdded()) { 162 | throw $exception; 163 | } 164 | 165 | return [$customer, $passwordHash]; 166 | } 167 | 168 | /** 169 | * Get attribute metadata. 170 | * 171 | * @param string $attributeCode 172 | * @return \Magento\Customer\Api\Data\AttributeMetadataInterface|null 173 | */ 174 | private function getAttributeMetadata($attributeCode) 175 | { 176 | try { 177 | return $this->customerMetadata->getAttributeMetadata($attributeCode); 178 | } catch (NoSuchEntityException $e) { 179 | return null; 180 | } 181 | } 182 | 183 | /** 184 | * @param \Magento\Customer\Api\Data\CustomerInterface $customer 185 | * @param InputException $exception 186 | * @return $this 187 | * @throws InputException 188 | */ 189 | private function validate(\Magento\Customer\Api\Data\CustomerInterface $customer, InputException $exception) 190 | { 191 | $username = $customer->getCustomAttribute('username')->getValue(); 192 | $websiteId = ($customer->getWebsiteId()) ? $customer->getWebsiteId() : null; 193 | 194 | $usernameAttribute = $this->getAttributeMetadata('username'); 195 | if ($usernameAttribute !== null && $usernameAttribute->isRequired() && '' == trim($username)) { 196 | throw InputException::requiredField('username'); 197 | } 198 | 199 | // Other rules are validated by the parent class because they are basic rules provided by Magento Core 200 | $inputValidation = $this->config->getValue(CustomerHelper::CFG_INPUT_VALIDATION); 201 | $useInputValidation = ($inputValidation == 'default' || $inputValidation == 'custom') ? true : false; 202 | 203 | if ($useInputValidation) { 204 | $validate = '/^*$/'; 205 | switch ($inputValidation) { 206 | case 'default': 207 | $validate = '/^[\w-]*$/'; 208 | break; 209 | case 'custom': 210 | $validate = $this->config->getValue(CustomerHelper::CFG_INPUT_VALIDATION_CUSTOM); 211 | break; 212 | } 213 | 214 | // if (!$this->config->isSetFlag('username/general/case_sensitive')) { 215 | // $validate .= 'i'; 216 | // } 217 | 218 | $validate = new \Zend_Validate_Regex($validate); 219 | 220 | if (!$validate->isValid($username)) { 221 | if ($inputValidation == 'custom') { 222 | $message = new \Magento\Framework\Phrase($this->config->getValue(Customer::CFG_INPUT_VALIDATION_CUSTOM_MESSAGE)); 223 | } else { 224 | $message = __('Username is invalid! Only letters, digits and \'_-\' values are accepted.'); 225 | } 226 | $exception->addError($message); 227 | } 228 | } 229 | 230 | $customerFound = $this->customerHelper->customerUsernameExists($username, $websiteId); 231 | if ($customerFound && $customerFound->getId() != $customer->getId()) { 232 | $message = __('Username already exists'); 233 | $exception->addError($message); 234 | } 235 | 236 | return $this; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Open Software License ("OSL") v. 3.0 3 | 4 | This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: 5 | 6 | Licensed under the Open Software License version 3.0 7 | 8 | 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: 9 | 10 | 1. to reproduce the Original Work in copies, either alone or as part of a collective work; 11 | 12 | 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; 13 | 14 | 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; 15 | 16 | 4. to perform the Original Work publicly; and 17 | 18 | 5. to display the Original Work publicly. 19 | 20 | 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. 21 | 22 | 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. 23 | 24 | 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. 25 | 26 | 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). 27 | 28 | 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. 29 | 30 | 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. 31 | 32 | 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. 33 | 34 | 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). 35 | 36 | 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. 37 | 38 | 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. 39 | 40 | 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. 41 | 42 | 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. 43 | 44 | 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 45 | 46 | 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. 47 | 48 | 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. -------------------------------------------------------------------------------- /view/frontend/templates/form/register.phtml: -------------------------------------------------------------------------------- 1 | 10 | 17 | getChildHtml('form_fields_before')?> 18 | 19 | getChildHtml('customer.form.register.extra')?> 20 |
21 | getBlockHtml('formkey'); ?> 22 |
23 |
24 | 25 | 26 | getLayout()->createBlock('Magento\Customer\Block\Widget\Name')->setObject($block->getFormData())->setForceUseCustomerAttributes(true)->toHtml() ?> 27 |
28 | 29 |
30 | 31 |
32 |
33 | getLayout()->createBlock('Diglin\Username\Block\Widget\Username') ?> 34 | isEnabled() && $_username->isEditable()): ?> 35 | setUsername($block->getFormData()->getUsername()) 37 | ->setObject($block->getFormData()) 38 | ->setIsEditable(true) 39 | ->toHtml() ?> 40 | 41 | isNewsletterEnabled()): ?> 42 | 46 | 47 | getChildHtml('customer.form.register.newsletter')?> 48 | 49 | 50 | getLayout()->createBlock('Magento\Customer\Block\Widget\Dob') ?> 51 | isEnabled()): ?> 52 | setDate($block->getFormData()->getDob())->toHtml() ?> 53 | 54 | 55 | getLayout()->createBlock('Magento\Customer\Block\Widget\Taxvat') ?> 56 | isEnabled()): ?> 57 | setTaxvat($block->getFormData()->getTaxvat())->toHtml() ?> 58 | 59 | 60 | getLayout()->createBlock('Magento\Customer\Block\Widget\Gender') ?> 61 | isEnabled()): ?> 62 | setGender($block->getFormData()->getGender())->toHtml() ?> 63 | 64 |
65 | getShowAddressFields()): ?> 66 |
67 |
68 | 69 |
70 | 71 |
72 | 73 |
74 |
75 |
76 | 77 |
78 | 79 |
80 |
81 | 82 | helper('Magento\Customer\Helper\Address')->getAttributeValidationClass('street'); ?> 83 | 84 |
85 | 86 |
87 | 88 |
89 | 90 | helper('Magento\Customer\Helper\Address')->getStreetLines(); $_i <= $_n; $_i++): ?> 91 |
92 | 95 |
96 | 97 |
98 |
99 | 100 |
101 |
102 |
103 | 104 |
105 | 106 |
107 | 108 |
109 |
110 | 111 |
112 | 113 |
114 | 117 | 118 |
119 |
120 | 121 |
122 | 123 |
124 | 125 |
126 |
127 | 128 |
129 | 130 |
131 | getCountryHtmlSelect() ?> 132 |
133 |
134 | getChildBlock('customer_form_address_user_attributes');?> 135 | 136 | setEntityType('customer_address'); ?> 137 | setFieldIdFormat('address:%1$s')->setFieldNameFormat('address[%1$s]');?> 138 | restoreSessionData($addressAttributes->getMetadataForm(), 'address');?> 139 | setShowContainer(false)->toHtml()?> 140 | 141 | 142 | 143 |
144 | 145 | 146 | 173 |
174 |
175 | 176 |
177 |
178 | 179 |
180 |
181 |
182 | 213 | getShowAddressFields()): ?> 214 | 230 | 231 | --------------------------------------------------------------------------------