Vous êtes sur la page 1sur 13

How-To: Integrate WeChat as Login Option inside

Magento 2
Briefly description about how I did the integration of both platforms.

How-To: Integrate WeChat and Magento 2


Company: TMO
Module name: Customer.
Description: It will override some functions of the core Customer Login class.
1. Create the file structure for the new Company/Module

2. Register new module.


a. Create these 3 files:
i. In the module root folder: composer.json and registration.php

composer.json
{
"name": "tmo/customer",
"description": "Add functions to Magento Customer Module",
"require": {
"php": "~5.5.0|~5.6.0|~7.0.0"
},
"type": "magento2-module",
"version": "1.0.7",
"license": [
"OSL-3.0",
"AFL-3.0"
],
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Tmo\\Customer\\": ""
}
}
}

registration.php
<?php
use \Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Tmo_Customer', __DIR__);
?>

ii.

In etcfolder, module.xml:

module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Tmo_Customer" setup_version="1.0.24" />
</config>

b. Run a terminal inside php container:

docker exec -ti asiamagento2_php-fpm_1 bash

Then execute:

bin/magento module:enable --clear-static-content Tmo_Customer

To register and add the module to Magento 2.


3. Define a Model to use as dropdown menu inside backend configuration.
This menu defines button sizes.
a. Create the fileModel/Config/Source/ButtonSize.phpwith the next content:

ButtonSize.php
<?php
namespace Tmo\Customer\Model\Config\Source;
class ButtonSize implements \Magento\Framework\Option\ArrayInterface
{
/**
* @return array
*/
public function toOptionArray()
{
return [
['value' => 'small', 'label' => __('Small')],
['value' => 'medium', 'label' => __('Medium')],
['value' => 'large', 'label' => __('Large')]
];
}
}

4. Define Social Login parameters configuration in the backend


a. To add parameters to the core config file of Customer, create the file inside etc/adminhtml/system.xml, content
example:

system.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<system>
<section id="customer" translate="label" sortOrder="130" showInDefault="1"
showInWebsite="1" showInStore="1">
<group id="sociallogin" translate="label" sortOrder="92" showInDefault="1"
showInWebsite="1" showInStore="1">
<label>Social Login Options</label>
<field id="social_login_button_style" translate="label" type="select"
sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Size of social media login provider icons</label>
<source_model>Tmo\Customer\Model\Config\Source\ButtonSize</source_model>
</field>
<field id="social_login_enabled_wechat" translate="label comment"
type="select" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Use WeChat as Social Login</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<comment>Enables de customer to login using his existing WeChat
account.</comment>
</field>
<field id="social_login_appid_wechat" translate="label" type="text"
sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Wechat APP ID*</label>
</field>
<field id="social_login_secret_wechat" translate="label" type="text"
sortOrder="4" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Wechat Secret*</label>
</field>
<field id="social_login_token_wechat" translate="label" type="text"
sortOrder="5" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Token*</label>
</field>
</group>
</section>
</system>
</config>

5. Add custom customer attributes.


The varchar fields "social_uid", "social_oid" and "social_username" must be added.
a. Create the fileSetup/UpgradeData.php, example code:

Example of UpgradeData.php
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
$customerSetup->addAttribute(
\Magento\Customer\Model\Customer::ENTITY,
'social_oid',
[
'input'=>'text',
'type'=>'varchar',
'label'=>'Social OpenID',
'visible'=>false,
'required'=>false,
'system'=>false,
'position'=> 156
]
);
$customerSetup->getEavConfig()->getAttribute('customer', 'social_oid')
->setData('used_in_forms',
['customer_account_create','customer_account_edit','adminhtml_customer'])
->save();

b. Modify the module version in the file etc/module.xml, increment it. This is to tell Magento there are changes in
the module and it needs to update itself.
c. @PHP container terminal,check Magento database status, if it found changes it will show them:

bin/magento setup:db:status
The module code base doesn't match the DB schema and data.
Tmo_Customer
schema:
1.0.24 -> 1.0.25
Tmo_Customer
data:
1.0.24 -> 1.0.25
Run 'setup:upgrade' to update your DB schema and data.

d. Update Magento runing this code:

bin/magento setup:upgrade

6. Create provider class.


This is an abstract class which defines common methods for all providers, for example methods to get configuration, an
array of all providers.
Put that class in Model/Social/Login/Provider.php

Example #1 of Provider.php
abstract class Provider
{
const BUTTON_SMALL='small';
const BUTTON_MEDIUM='medium';
const BUTTON_LARGE='large';
const BUTTON_DEFAULT=self::BUTTON_SMALL;
const XML_PATH_SOCIAL_LOGIN_BUTTON='customer/sociallogin/social_login_button_style';
public static $impl= [
Providers\Wechat::TITLE=>Providers\Wechat::TYPE,
Providers\Facebook::TITLE=>Providers\Facebook::TYPE,
Providers\Weibo::TITLE=>Providers\Weibo::TYPE,
Providers\Douban::TITLE=>Providers\Douban::TYPE
];
public static $buttonStyles=[
self::BUTTON_SMALL=>'Small',
self::BUTTON_MEDIUM=>'Medium',
self::BUTTON_LARGE=>'Large'
];

Example #2 of Provider.php
public function name()
{
return $this->m_name;
}
public function title()
{
return $this->m_title;
}
public function domain()
{
return $this->m_domain;
}
public function template()
{
return "tmo/customer/view/frontend/templates/{$this->m_name}.phtml";
}
public function isEnabled()
{
return
1===(int)$this->_scopeConfig->getValue("customer/sociallogin/social_login_enabled_{$this->m_name}
");
}
public function appID()
{
return
$this->_scopeConfig->getValue("customer/sociallogin/social_login_appid_{$this->m_name}");
}
public function secretKey()
{
return
$this->_scopeConfig->getValue("customer/sociallogin/social_login_secret_{$this->m_name}");
}
public function authorizationUrl()
{
return
$this->_scopeConfig->getValue("customer/sociallogin/social_login_general_auth_url_{$this->m_name}
");
}

7. Create individual provider classes


These classes implements the particular workflow to get authorization to use the services of specific provider.
Put them inModel/Social/Login/Providers/

Example of Wechat.php
public function login(array $data_)
{
$strOauthAccessTokenURL = $this->oauhAccessTokenUrl();
$parameters['appid'] = $this->appID();
$parameters['secret'] = $this->secretKey();
$parameters['code'] = $data_['code'];
$parameters['grant_type'] = 'authorization_code';
$parameters['state'] = $data_['state'];
if (!$contents=$this->http($strOauthAccessTokenURL,$parameters,'GET'))
return null;
$result=json_decode($contents, true);
$openid = $result["openid"];
$access_token = $result["access_token"];
$strGetUserInfo = $this->userInfoUrl();
$parameters = array();
$parameters['access_token'] = $access_token;
$parameters['openid'] = $openid;
$parameters['state'] = $data_['state'];
if (!$contents=$this->http($strGetUserInfo,$parameters,'GET'))
return null;
$result=json_decode($contents, true);
if(false===isset($result["nickname"]))
return null;
...
...

8. Create template file


a. Create the fileview/frontend/templates/providers.phtml.For each provider enabled to show in login form, this class
renders a button (of size previously defined) with an URL to the authorization service.

providers.phtml
<table width="100">
<tr>
<?
$providers = \Tmo\Customer\Model\Social\Login\Provider::$impl;
foreach($providers as $name=>$type)
{
$providerClass = "Tmo\Customer\Model\Social\Login\Providers\\".$name;
$provider = new $providerClass($this->getMyScopeConfig());
if($provider->isEnabled())
{?>
<td>
<ol class="<?= $provider->name().' '.$provider->buttonSize(); ?> ">
<a href="<?= $block->getUri($provider) ?>" title="<?= $provider->name() ?>">
<img src="<?= $block->getImageUrl($provider) ?>" alt="<?= $provider->name()
?>Login"/>
</a>
</ol>
</td>
<?}
}
?>
</tr>
</table>

b. Create the fileview/frontend/templates/form/login.phtml. This file completely overrides the original core file.
Copy the original content into it and add the following lines at the end before the last </form> tag:

part of login.phtml
<div class="field note"><?php echo __('Or, sign in with the Social Media Provider of your
preference:') ?></div><br>
<div class="terciary">
<?php echo $block->getChildHtml('form_social_login'); ?>
</div>

c. Create the fileview/frontend/templates/form/newcustomer.phtml. This file completely overrides the original core
file. Copy the original content into it and add the following lines at the end before the last </div> tag:

part of newcustomers.phtml
<div id="login_container"></div>
<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
<script type="text/javascript">
var appVersion = navigator.appVersion;
var isWeChat = appVersion.indexOf("MicroMessenger");
if(isWeChat < 0 ){
var obj = new WxLogin({
id:"login_container",
appid: "wx9a4eb803e732bdec",
scope: "snsapi_login",
redirect_uri:"<?=UrlEncode('http://wechat.tmogroup.asia/getcode.php')?>",
state: "wechatqrcode",
style: "black",
href: ""
});
}
</script>

This piece of code will show the QR code to scan and log in using WeChat account, only when user is not using the
WeChat web browser.
9. Create layout. This file will tell Magento when to open which template and which block class is the owner of the
template.
a. Create fileview/frontend/layout/customer_account_login.xml. This file completely overrides the original core file.
Copy the original content into it and add the following lines:

parto of customer_account_login.xml
<block class="Magento\Customer\Block\Form\Login" name="customer_form_login"
template="Tmo_Customer::form/login.phtml">
<container name="form.additional.info" as="form_additional_info"/>
<container name="form.social.login" as="form_social_login"/>
</block>

part of customer_account_login.xml
<block class="Magento\Customer\Block\Form\Login\Info" name="customer.new"
template="Tmo_Customer::newcustomer.phtml">
<container name="form.qrcode.wechat.login" as="form_qrcode_wechat_login"/>
</block>

part of customer_account_login.xml
<referenceContainer name="form.social.login">
<block class="Tmo\Customer\Block\RenderProvider" name="form_social_login_customer"
template="Tmo_Customer::providers.phtml"/>
</referenceContainer>

Note that the blocks still define the original class but with different template.
10.

10.

Create a block to write the html code which render the social media providers.
a. Create the fileBlock/RenderProvider.php. This file will initialize all the properties required to render html to
the screen using templates, and also provide all the functionality (constructors, methods, functions, etc) to the
template files.

Example of class RenderProvider.php


public function getUri($provider)
{
$provider_name = $provider->name();
switch($provider_name)
{
case 'wechat':
$uri = $provider->authorizationUrl();
$appID = $provider->appID();
$redirect_uri =
"http://magento2.asia/index.php/customer/account/login/provider/".$provider_name;
$response_type = "code";
$state = 'wechatbrowser';
$scope = "snsapi_login";
$uri .=
"?appid=$appID&redirect_uri=$redirect_uri&response_type=$response_type&state=$state&scope=$
scope";
break;
default:
$uri = 'http://magento2.asia/index.php/customer/account/login/';
break;
}
return $uri;
}

11.

Create the plugin to override core login actions.


A plugin is a new implementation of Magento 2 and it's defined to instead of re-write already defined class, add
functionality before or after the execution of the original function OR completely override it.
a. Create the fileetc/di.xml. This file defines what class will be overrided by what plugin class.

di.xml
<config>
<type name="Magento\Customer\Controller\Account\Login">
<plugin name="controller_social_login_plugin"
type="Tmo\Customer\Controller\Account\Plugin"
sortOrder="10"
disabled="false"/>
</type>
<type name="Magento\Customer\Block\Form\Login">
<plugin name="customer_block_form_login_plugin"
type="Tmo\Customer\Block\Form\Plugin"
sortOrder="5"
disabled="false"/>
</type>
<preference for="Tmo\Customer\Model\Social\Login\Provider_wechat"
type="Tmo\Customer\Model\Social\Login\Providers\Wechat" />
<preference for="Tmo\Customer\Model\Social\Login\Provider_facebook"
type="Tmo\Customer\Model\Social\Login\Providers\Facebook" />
</config>

This file also defines something new in Magento 2: "preferences". Briefly, this preferences tells to Magento "when
you'll see this string create an instance of this type", and basically they are used in the constructors for
something also new called automatic dependency injection, I'll write about it in another article.
b. Create the fileController/Account/Plugin.php. This is finally the plugin class which implements all the previous
defined functions. The next diagram explains how this plugin works:

The plugin will intercept the core functionality of login module, it will check if there is a CODE and a PROVIDER
in the URL, if that's there plugin will get the configuration of the provider, will try to connect to the
authorization service to get the user information, will check if the user already exists, if it does will redirect
it to the dashboard but if it doesn't will register it into the database, and the redirect it to its dashboard.

Related articles
How-To: WeChat as Social Login (Part 1)
How-To: Wechat as Social Login (Part 2)

Vous aimerez peut-être aussi