Monday, June 12, 2017

Laravel 5.X Authentication Custom User Providers

The custom provider let you make and bridge between your user custom authentication service and the Laravel functionality. It's easy to implement, below show full process step by step.

Stage 1: Create a User model class ->

At first you need to create a model class which will extend laravel custom model Illuminate\Foundation\Auth\User as below:

<?php
namespace App\Entity;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    /**
     * The attributes that are assignable.
     */
    protected $fillable = [
        'first_name', 'last_name'
    ];

    /**
     * The attributes excluded from the model's JSON form.
     */
    protected $hidden = [
        'password', 'remember_token'
    ];
}


Stage 2: Create a CustomValidationProvider (Data Checker) class ->


<?php
namespace App\Authentication;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;

class CustomValidationProvider implements UserProvider
{
    public function __construct($model)
    {
        $this->model = $model;
    }

    public function retrieveById($identifier)
    {
        /* Get by id */
        return $this->createModel()->newQuery()->find($identifier);
    }

    public function retrieveByToken($identifier, $token)
    {
        $model = $this->createModel();

        return $model->newQuery()
            ->where($model->getAuthIdentifierName(), $identifier)
            ->where($model->getRememberTokenName(), $token)
            ->first();
    }

    public function updateRememberToken(Authenticatable $user, $token)
    {
        $user->setRememberToken($token);
        $user->save();
    }

    public function retrieveByCredentials(array $credentials)
    {
        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (!contains($key, 'password')) {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }

    public function validateCredentials(Authenticatable $user, array $credentials)
    {
        /* Match password here */
        return $user->getAuthPassword() == $credentials["password"];
    }

    public function createModel()
    {
        $class = '\\'.ltrim($this->model, '\\');
        return new $class;
    }

    static function contains($haystack, $needle)
    {
        return strpos($haystack, $needle) !== false;
    }
}

Don’t forget to register this service in your config/app.php file as below line:


'providers' => [
    App\Authentication\CustomAuthServiceProvider::class,
    ......
]

Stage 3: Register custom provider (Initialization of Provider) ->

<?php
namespace App\Authentication;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\ServiceProvider;

class CustomAuthServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Auth::provider('custom_provider', function($app, array $config) {
            return new CustomValidationProvider($config['model']);
        });
    }

    public function register()
    {

    }
}

Stage 4: Update config to use new driver ->

Open up your config/auth.php file and scroll down to the "providers" section, and simply update the driver name as shown:


'providers' => [
    'users' => [
        'driver' => 'custom_provider',
        'model' => App\Entity\User::class,
    ]
]


Again, I can’t tell you how to implement these methods as it depends on how and where you’re storing your users, but as an example, you might inject an API provider via the constructor, and then make API calls to get user data, apply it to an instance of our user class, then return it.



Saturday, June 10, 2017

PayWay Rest API: Create Refund From PayWay Payment

You can visit PayWay rest api documentation page:
https://www.payway.com.au/docs/rest.html#refund-a-payment

PayWay Rest API: Check if Rest API credentials are valid

PayWay Rest API: Create Customer Create Token


<?php
include_once "CurlExecutor.php";

define("BASE_URL", "https://api.payway.com.au/rest/v1");
define("MERCHANT_ID", "TEST");
define("PRIVATE_KEY", "T10487_SEC_...");
define("PUBLIC_KEY", "T10487_PUB_...");

createRefundOfPayment();

function createRefundOfPayment() {
    $headers[] = "Authorization: Basic " . base64_encode(PRIVATE_KEY . ":");
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    $post = array(
        "parentTransactionId" => "1956258559",
        "transactionType" => "refund",
        "principalAmount" => "23.45",
        "orderNumber" => "RefundIdentification"
    );

    $result = CurlExecutor::execute(BASE_URL . "/transactions", "POST", $post, null, $headers);
    $result["response"] = json_decode($result["response"]);
    CurlExecutor::prettyPrint($result);
}
?>


And output is below:


Array
(
    [code] => 201
    [response] => stdClass Object
        (
            [transactionId] => 1958000143
            [receiptNumber] => 1958000143
            [status] => approved
            [responseCode] => 08
            [responseText] => Honour with identification
            [transactionType] => refund
            [customerNumber] => 5
            [customerName] => Hexa Lucio
            [customerEmail] => hexa@bitmascot.com
            [orderNumber] => RefundIdentification
            [currency] => aud
            [principalAmount] => -23.45
            [surchargeAmount] => 0
            [paymentAmount] => -23.45
            [paymentMethod] => creditCard
            [creditCard] => stdClass Object
                (
                    [cardNumber] => 456471...004
                    [expiryDateMonth] => 02
                    [expiryDateYear] => 19
                    [cardScheme] => visa
                    [cardholderName] => Hexa Lucio Tony
                )

            [merchant] => stdClass Object
                (
                    [merchantId] => TEST
                    [merchantName] => Test Merchant
                    [links] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [rel] => self
                                    [href] => https://api.payway.com.au/rest/v1/merchants/TEST
                                )

                        )

                )

            [transactionDateTime] => 10 Jun 2017 13:24 AEST
            [settlementDate] => 10 Jun 2017
            [parentTransaction] => stdClass Object
                (
                    [transactionId] => 1956258559
                    [receiptNumber] => 1956258559
                    [status] => approved
                    [transactionType] => payment
                    [customerNumber] => 5
                    [orderNumber] => INV-GGO-ABA-460
                    [currency] => aud
                    [paymentAmount] => 99.25
                    [settlementDate] => 08 Jun 2017
                )

            [isVoidable] => 1
            [isRefundable] => 
            [links] => Array
                (
                    [0] => stdClass Object
                        (
                            [rel] => self
                            [href] => https://api.payway.com.au/rest/v1/transactions/1958000143
                        )

                    [1] => stdClass Object
                        (
                            [rel] => void
                            [href] => https://api.payway.com.au/transactions/1958000143/void
                        )

                    [2] => stdClass Object
                        (
                            [rel] => parent
                            [href] => https://api.payway.com.au/rest/v1/transactions/1956258559
                        )

                )

        )

)





PayWay Rest API: Create Payment Using Stored Credit Card Token

It's easy to store credit card in PayWay and create payment using that that credit card token.

PayWay Rest API: Check if Rest API credentials are valid

PayWay Rest API: Create Customer Create Token

Below is a PHP script to create payment using stored credit card token:


<?php
include_once "CurlExecutor.php";

define("BASE_URL", "https://api.payway.com.au/rest/v1");
define("MERCHANT_ID", "TEST");
define("PRIVATE_KEY", "T10487_SEC_...");
define("PUBLIC_KEY", "T10487_PUB_...");

createTokenPayment();

function createTokenPayment() {
    $headers[] = "Authorization: Basic " . base64_encode(PRIVATE_KEY . ":");
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    $post = array(
        "customerNumber" => 7,
        "merchantId" => MERCHANT_ID,
        "transactionType" => "payment",
        "principalAmount" => "23.45",
        "currency" => "aud",
        "orderNumber" => "Sale-Identification"
    );

    $result = CurlExecutor::execute(BASE_URL . "/transactions", "POST", $post, null, $headers);
    $result["response"] = json_decode($result["response"]);
    CurlExecutor::prettyPrint($result);
}
?>

Output as below:


Array
(
    [code] => 201
    [response] => stdClass Object
        (
            [transactionId] => 1957977083
            [receiptNumber] => 1957977083
            [status] => approved
            [responseCode] => 08
            [responseText] => Honour with identification
            [transactionType] => payment
            [customerNumber] => 7
            [customerName] => Pritom
            [customerEmail] => pritomkucse@gmail.com
            [orderNumber] => Sale-Identification
            [currency] => aud
            [principalAmount] => 23.45
            [surchargeAmount] => 0
            [paymentAmount] => 23.45
            [paymentMethod] => creditCard
            [creditCard] => stdClass Object
                (
                    [cardNumber] => 516320...008
                    [expiryDateMonth] => 08
                    [expiryDateYear] => 20
                    [cardScheme] => mastercard
                    [cardholderName] => My Mastercard
                )

            [merchant] => stdClass Object
                (
                    [merchantId] => TEST
                    [merchantName] => Test Merchant
                    [links] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [rel] => self
                                    [href] => https://api.payway.com.au/rest/v1/merchants/TEST
                                )

                        )

                )

            [transactionDateTime] => 10 Jun 2017 13:09 AEST
            [settlementDate] => 10 Jun 2017
            [isVoidable] => 1
            [isRefundable] => 
            [links] => Array
                (
                    [0] => stdClass Object
                        (
                            [rel] => self
                            [href] => https://api.payway.com.au/rest/v1/transactions/1957977083
                        )

                    [1] => stdClass Object
                        (
                            [rel] => void
                            [href] => https://api.payway.com.au/transactions/1957977083/void
                        )

                )

        )

)








PayWay Rest API: Create Customer Create Token

You can create token in PayWay portal using credit card details to use further that token to create payment.

PayWay Rest API: Check if Rest API credentials are valid

If you are interested more on PayWay Rest API you can visit the below link:

https://www.payway.com.au/docs/rest.html

Below is a PHP script to create token using credit card etails. Be aware that below code snippet used both private and public key in different section.



<?php
include_once "CurlExecutor.php";

define("BASE_URL", "https://api.payway.com.au/rest/v1");
define("MERCHANT_ID", "TEST");
define("PRIVATE_KEY", "T10487_SEC_...");
define("PUBLIC_KEY", "T10487_PUB_...");

createCustomer(getSingleUseToken());

function createCustomer($token) {
    $headers[] = "Authorization: Basic " . base64_encode(PRIVATE_KEY . ":");
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    $post = array(
        "singleUseTokenId" => $token,
        "merchantId" => MERCHANT_ID,
        "customerName" => "Pritom",
        "emailAddress" => "pritomkucse@gmail.com"
    );

    $result = CurlExecutor::execute(BASE_URL . "/customers", "POST", $post, null, $headers);
    $result["response"] = json_decode($result["response"]);
    CurlExecutor::prettyPrint($result);
}

function getSingleUseToken() {
    $headers[] = "Authorization: Basic " . base64_encode(PUBLIC_KEY . ":");
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    $post = array(
        "paymentMethod" => "creditCard",
        "cardNumber" => "5163200000000008",
        "cardholderName" => "My Mastercard",
        "cvn" => "070",
        "expiryDateMonth" => "08",
        "expiryDateYear" => "20",
    );

    $result = CurlExecutor::execute(BASE_URL . "/single-use-tokens", "POST", $post, null, $headers);
    $result["response"] = json_decode($result["response"]);
    if ($result["code"] == 200) {
        return $result["response"]->singleUseTokenId;
    }
    CurlExecutor::prettyPrint($result);
    die("Error");
}
?>

Output is below:


Array
(
    [code] => 201
    [response] => stdClass Object
        (
            [customerNumber] => 7
            [paymentSetup] => stdClass Object
                (
                    [paymentMethod] => creditCard
                    [stopped] => 
                    [creditCard] => stdClass Object
                        (
                            [cardNumber] => 516320...008
                            [expiryDateMonth] => 08
                            [expiryDateYear] => 20
                            [cardScheme] => mastercard
                            [cardholderName] => My Mastercard
                            [surchargePercentage] => 0
                        )

                    [merchant] => stdClass Object
                        (
                            [merchantId] => TEST
                            [merchantName] => Test Merchant
                            [links] => Array
                                (
                                    [0] => stdClass Object
                                        (
                                            [rel] => self
                                            [href] => https://api.payway.com.au/rest/v1/merchants/TEST
                                        )

                                )

                        )

                )

            [contact] => stdClass Object
                (
                    [customerName] => Pritom
                    [emailAddress] => pritomkucse@gmail.com
                    [sendEmailReceipts] => 
                    [phoneNumber] => 
                    [address] => stdClass Object
                        (
                            [street1] => 
                            [street2] => 
                            [cityName] => 
                            [state] => 
                            [postalCode] => 
                        )

                )

            [customFields] => stdClass Object
                (
                )

            [links] => Array
                (
                    [0] => stdClass Object
                        (
                            [rel] => self
                            [href] => https://api.payway.com.au/rest/v1/customers/7
                        )

                    [1] => stdClass Object
                        (
                            [rel] => help
                            [href] => https://www.payway.com.au/docs/rest.html#customers
                        )

                    [2] => stdClass Object
                        (
                            [rel] => contact
                            [href] => https://api.payway.com.au/rest/v1/customers/7/contact
                        )

                    [3] => stdClass Object
                        (
                            [rel] => custom-fields
                            [href] => https://api.payway.com.au/rest/v1/customers/7/custom-fields
                        )

                    [4] => stdClass Object
                        (
                            [rel] => payment-setup
                            [href] => https://api.payway.com.au/rest/v1/customers/7/payment-setup
                        )

                    [5] => stdClass Object
                        (
                            [rel] => schedule
                            [href] => https://api.payway.com.au/rest/v1/customers/7/schedule
                        )

                    [6] => stdClass Object
                        (
                            [rel] => virtual-account
                            [href] => https://api.payway.com.au/rest/v1/customers/7/virtual-account
                        )

                    [7] => stdClass Object
                        (
                            [rel] => search-customer-transactions
                            [href] => https://api.payway.com.au/rest/v1/transactions/search-customer?customerNumber=7
                        )

                )

        )

)





PayWay Rest API: Create Credit Card Payment

If you are not already check connection to PayWay Rest API, you need to do that validation. Follow the below link to test API connection, there you can learn about public and private key.


If you are interested more on PayWay Rest API you can visit the below link:

https://www.payway.com.au/docs/rest.html

Below is a PHP script to create credit card payment. Be aware that below code snippet used both private and public key in different section.


<?php
include_once "CurlExecutor.php";

define("BASE_URL", "https://api.payway.com.au/rest/v1");
define("MERCHANT_ID", "TEST");
define("PRIVATE_KEY", "T10487_SEC_...");
define("PUBLIC_KEY", "T10487_PUB_...");

createPayment(getSingleUseToken());

function createPayment($token) {
    $headers[] = "Authorization: Basic " . base64_encode(PRIVATE_KEY . ":");
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    $post = array(
        "singleUseTokenId" => $token,
        "customerNumber" => "Customer-ID",
        "transactionType" => "payment",
        "principalAmount" => "12.34",
        "currency" => "aud",
        "orderNumber" => "Sale-Identification",
        "merchantId" => MERCHANT_ID
    );

    $result = CurlExecutor::execute(BASE_URL . "/transactions", "POST", $post, null, $headers);
    $result["response"] = json_decode($result["response"]);
    CurlExecutor::prettyPrint($result);
}

function getSingleUseToken() {
    $headers[] = "Authorization: Basic " . base64_encode(PUBLIC_KEY . ":");
    $headers[] = "Content-Type: application/x-www-form-urlencoded";

    $post = array(
        "paymentMethod" => "creditCard",
        "cardNumber" => "5163200000000008",
        "cardholderName" => "My Mastercard",
        "cvn" => "070",
        "expiryDateMonth" => "08",
        "expiryDateYear" => "20",
    );

    $result = CurlExecutor::execute(BASE_URL . "/single-use-tokens", "POST", $post, null, $headers);
    $result["response"] = json_decode($result["response"]);
    if ($result["code"] == 200) {
        return $result["response"]->singleUseTokenId;
    }
    CurlExecutor::prettyPrint($result);
    die("Error");
}
?>



Below is output of valid payment:


Array
(
    [code] => 201
    [response] => stdClass Object
        (
            [transactionId] => 1957973936
            [receiptNumber] => 1957973936
            [status] => approved
            [responseCode] => 08
            [responseText] => Honour with identification
            [transactionType] => payment
            [customerNumber] => CUSTOMER-ID
            [customerName] => My Mastercard
            [orderNumber] => Sale-Identification
            [currency] => aud
            [principalAmount] => 12.34
            [surchargeAmount] => 0
            [paymentAmount] => 12.34
            [paymentMethod] => creditCard
            [creditCard] => stdClass Object
                (
                    [cardNumber] => 516320...008
                    [expiryDateMonth] => 08
                    [expiryDateYear] => 20
                    [cardScheme] => mastercard
                    [cardholderName] => My Mastercard
                )

            [merchant] => stdClass Object
                (
                    [merchantId] => TEST
                    [merchantName] => Test Merchant
                    [links] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [rel] => self
                                    [href] => https://api.payway.com.au/rest/v1/merchants/TEST
                                )

                        )

                )

            [transactionDateTime] => 10 Jun 2017 11:57 AEST
            [settlementDate] => 10 Jun 2017
            [isVoidable] => 1
            [isRefundable] => 
            [links] => Array
                (
                    [0] => stdClass Object
                        (
                            [rel] => self
                            [href] => https://api.payway.com.au/rest/v1/transactions/1957973936
                        )

                    [1] => stdClass Object
                        (
                            [rel] => void
                            [href] => https://api.payway.com.au/transactions/1957973936/void
                        )

                )

        )

)

And you can see that in PayWay portal there is a payment created:


Error response from PayWay Rest API is well defined. So you can capture error response easily.


PayWay Rest API: Check if Rest API credentials are valid

PayWay Rest API is easy to implement. We need three information from PayWay end to create payment, refund payment, void payment, store credit card for further use and many other things.

So we need:
1. Publishable public key
2. Secret private key



3. and Merchant ID



Now you have all 3 information to communicate with PayWay.

Below is a PHP script to test credentials using rest API:


<?php
include_once "CurlExecutor.php";

define("BASE_URL", "https://api.payway.com.au/rest/v1");
define("MERCHANT_ID", "TEST");
define("PRIVATE_KEY", "T10487_SEC_...");
define("PUBLIC_KEY", "T10487_PUB_...");

$headers[] = "Authorization: Basic " . base64_encode(PUBLIC_KEY . ":");
$result = CurlExecutor::execute(BASE_URL, "GET", null, null, $headers);
$result["response"] = json_decode($result["response"]);
CurlExecutor::prettyPrint($result);
?>


If your credentials are fine below output will back from PayWay end:


Array
(
    [code] => 200
    [response] => stdClass Object
        (
            [clientNumber] => T52943
            [clientName] => Pritom
            [keyName] => T10487_PUB...bzq
            [links] => Array
                (
                    [0] => stdClass Object
                        (
                            [rel] => single-use-tokens
                            [href] => https://api.payway.com.au/rest/v1/single-use-tokens
                        )

                    [1] => stdClass Object
                        (
                            [rel] => surcharges
                            [href] => https://api.payway.com.au/rest/v1/surcharges
                        )

                    [2] => stdClass Object
                        (
                            [rel] => help
                            [href] => https://www.payway.com.au/docs/rest.html#resources
                        )

                )

        )

)
If you have error in your public key below output will be generated:


Array
(
    [code] => 401
    [response] => stdClass Object
        (
            [message] => The "Authorization" header contained an unknown API key. You must send your API key as the basic authentication username.
            [links] => Array
                (
                    [0] => stdClass Object
                        (
                            [rel] => help
                            [href] => https://www.payway.com.au/docs/rest.html#authentication
                        )

                )

        )

)


Friday, June 9, 2017

Lock wait timeout exceeded; try restarting transaction

Why is happening like this, some other thread is holding a record lock on some record (you're updating every record in the table!) for too long, and your thread is being timed out. That's why you got this error.

Your first step to lookup for which queries this problem happened.
Below are some queries to observe transaction status and other data:

show open tables where in_use > 0;
show processlist;
SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`;
SELECT * FROM `information_schema`.`innodb_locks`;
show variables like 'innodb_lock_wait_timeout';
show variables like '%wait_timeout%';

Above queries help you to find out why the problem occurs. 

Now you can check your database transaction isolation level in the mysql using following command:

SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation;

I think all values are set to "REPEATABLE-READ" if you don't configured it yet.

Make sure the database tables are using InnoDB storage engine and READ-COMMITTED transaction isolation level.

Now you can set it to "READ-COMMITTED" for better performance using below command:

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

If the the above configuration is correct then please try to increase the database server innodb_lock_wait_timeout variable to 500 (it's a random value, default value is 50).

Restart MySQL database service for the configuration to take place.

Modify MySQL startup options in the configuration file my.cnf (often named my.ini on Windows), so the transaction level is set to transaction-isolation = READ-COMMITTED.

And

innodb_lock_wait_timeout=500

If this not helps you much, you need and database administration as well as expert to troubleshoot the problem.