<?php

namespace FondOfSpryker\Zed\AvailabilityAlert\Persistence;

use Orm\Zed\AvailabilityAlert\Persistence\Map\FosAvailabilityAlertSubscriptionTableMap;
use Spryker\Zed\Kernel\Persistence\AbstractQueryContainer;

/**
 * @method \FondOfSpryker\Zed\AvailabilityAlert\Persistence\AvailabilityAlertPersistenceFactory getFactory()
 */
class AvailabilityAlertQueryContainer extends AbstractQueryContainer implements AvailabilityAlertQueryContainerInterface
{
    /**
     * @param string $email
     * @param int $idProductAbstract
     * @param int $status
     *
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function querySubscriptionByEmailAndIdProductAbstractAndStatus($email, $idProductAbstract, $status)
    {
        return $this->querySubscriptionByEmailAndIdProductAbstract($email, $idProductAbstract)
            ->filterByStatus($status);
    }

    /**
     * @param string $email
     * @param int $idProductAbstract
     *
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function querySubscriptionByEmailAndIdProductAbstract($email, $idProductAbstract)
    {
        return $this->querySubscription()
            ->filterByEmail($email)
            ->filterByFkProductAbstract($idProductAbstract);
    }

    /**
     * @api
     *
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function querySubscription()
    {
        return $this->getFactory()->createAvailabilityAlertSubscriptionQuery();
    }

    /**
     * @param int $status
     *
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function querySubscriptionsByStatus($status)
    {
        return $this->querySubscription()
            ->filterByStatus($status);
    }

    /**
     * @param int $status
     * @param int $idStore
     *
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function querySubscriptionsByIdStoreAndStatus($idStore, $status)
    {
        return $this->querySubscription()
            ->filterByFkStore($idStore)
            ->filterByStatus($status);
    }

    /**
     * @param int $idProductAbstract
     * @param int $status
     *
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function querySubscriptionsByIdProductAbstractAndStatus($idProductAbstract, $status)
    {
        return $this->querySubscriptionsByStatus($status)
            ->filterByFkProductAbstract($idProductAbstract);
    }

    /**
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscriptionQuery
     */
    public function queryCountOfSubscriberPerProductAbstract()
    {
        return $this->querySubscriptionsByStatus(FosAvailabilityAlertSubscriptionTableMap::COL_STATUS_PENDING)
            ->withColumn('COUNT(*)', 'count_of_subscriber')
            ->select(['count_of_subscriber', FosAvailabilityAlertSubscriptionTableMap::COL_FK_PRODUCT_ABSTRACT])
            ->groupByFkProductAbstract();
    }
}


<?php

namespace FondOfSpryker\Zed\AvailabilityAlert\Business\Model;

use DateTime;
use FondOfSpryker\Zed\AvailabilityAlert\Persistence\AvailabilityAlertQueryContainerInterface;
use Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscription;
use Orm\Zed\AvailabilityAlert\Persistence\Map\FosAvailabilityAlertSubscriptionTableMap;
use Orm\Zed\Store\Persistence\SpyStoreQuery;
use Spryker\Shared\Kernel\Store;
use Spryker\Zed\Availability\Business\AvailabilityFacadeInterface;

class SubscribersNotifier implements SubscribersNotifierInterface
{
    /**
     * @var \Spryker\Zed\Availability\Business\AvailabilityFacadeInterface
     */
    protected $availabilityFacade;

    /**
     * @var \FondOfSpryker\Zed\AvailabilityAlert\Persistence\AvailabilityAlertQueryContainerInterface
     */
    protected $queryContainer;

    /**
     * @var \FondOfSpryker\Zed\AvailabilityAlert\Business\Model\MailHandler
     */
    protected $mailHandler;

    /**
     * @var int
     */
    protected $minimalPercentageDifference;

    /**
     * @param \Spryker\Zed\Availability\Business\AvailabilityFacadeInterface $availabilityFacade
     * @param \FondOfSpryker\Zed\AvailabilityAlert\Business\Model\MailHandler $mailHandler
     * @param \FondOfSpryker\Zed\AvailabilityAlert\Persistence\AvailabilityAlertQueryContainerInterface $queryContainer
     * @param int $minimalPercentageDifference
     */
    public function __construct(
        AvailabilityFacadeInterface $availabilityFacade,
        MailHandler $mailHandler,
        AvailabilityAlertQueryContainerInterface $queryContainer,
        $minimalPercentageDifference
    ) {
        $this->availabilityFacade = $availabilityFacade;
        $this->mailHandler = $mailHandler;
        $this->queryContainer = $queryContainer;
        $this->minimalPercentageDifference = $minimalPercentageDifference;
    }

    /**
     * @return \FondOfSpryker\Zed\AvailabilityAlert\Business\Model\SubscribersNotifier
     */
    public function notify()
    {
        $countOfSubscriberPerProductAbstract = $this->getCountOfSubscriberPerProductAbstract();

        foreach ($this->getSubscritpions() as $fosAvailabilityAlertSubscription) {
            if (!$this->canSendNotification($fosAvailabilityAlertSubscription, $countOfSubscriberPerProductAbstract)) {
                continue;
            }

            $this->sendNotification($fosAvailabilityAlertSubscription);
        }

        return $this;
    }

    /**
     * @param \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription
     *
     * @return \FondOfSpryker\Zed\AvailabilityAlert\Business\Model\SubscribersNotifier
     */
    protected function sendNotification(FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription)
    {
        $this->mailHandler->sendAvailabilityAlertMail($fosAvailabilityAlertSubscription);

        $fosAvailabilityAlertSubscription->setSentAt(new DateTime())
            ->setStatus(FosAvailabilityAlertSubscriptionTableMap::COL_STATUS_NOTIFIED)
            ->save();

        return $this;
    }

    /**
     * @param \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription
     * @param array $countOfSubscriberPerProductAbstract
     *
     * @return bool
     */
    protected function canSendNotification(
        FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription,
        $countOfSubscriberPerProductAbstract
    ) {
        $percentageDifference = $this->calculatePercentageDifference(
            $fosAvailabilityAlertSubscription,
            $countOfSubscriberPerProductAbstract
        );

        return $percentageDifference > $this->minimalPercentageDifference;
    }

    /**
     * @param \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription
     * @param array $countOfSubscriberPerProductAbstract
     *
     * @return float|int
     */
    protected function calculatePercentageDifference(
        FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription,
        $countOfSubscriberPerProductAbstract
    ) {
        $fkProductAbstract = $fosAvailabilityAlertSubscription->getFkProductAbstract();
        $subscriberCount = $countOfSubscriberPerProductAbstract[$fkProductAbstract];
        $availability = $this->getAvailability($fosAvailabilityAlertSubscription);

        return $availability * 100 / $subscriberCount;
    }

    /**
     * @param \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription
     *
     * @return int
     */
    protected function getAvailability(
        FosAvailabilityAlertSubscription $fosAvailabilityAlertSubscription
    ) {
        $productAbstractAvailability = $this->availabilityFacade->getProductAbstractAvailability(
            $fosAvailabilityAlertSubscription->getFkProductAbstract(),
            $fosAvailabilityAlertSubscription->getFkLocale()
        );

        return $productAbstractAvailability->getAvailability();
    }

    /**
     * @return \Orm\Zed\AvailabilityAlert\Persistence\FosAvailabilityAlertSubscription[]|\Propel\Runtime\Collection\ObjectCollection
     */
    protected function getSubscritpions()
    {
        $idStore = $this->getIdStorebyStoreName(Store::getInstance()->getStoreName());

        return $this->queryContainer
            ->querySubscriptionsByIdStoreAndStatus($idStore, 0)
            ->find();
    }

    /**
     * @return array
     */
    protected function getCountOfSubscriberPerProductAbstract()
    {
        return $this->queryContainer->queryCountOfSubscriberPerProductAbstract()
            ->find()
            ->toKeyValue(FosAvailabilityAlertSubscriptionTableMap::COL_FK_PRODUCT_ABSTRACT, 'count_of_subscriber');
    }

    /**
     * @param string $storeName
     *
     * @return int
     */
    protected function getIdStorebyStoreName(string $storeName): int
    {

        $storeEntity = SpyStoreQuery::create()
            ->filterByName($storeName)
            ->findOne();

        if ($storeEntity == null) {
            return 0;
        }

        return $storeEntity->getIdStore();
    }
}


<?php
/**
 * This file is part of the EkiPayumBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Bridge\Symfony\Action;

use Eki\Payum\Nganluong\Request\GetPaymentMethod;
use Eki\Payum\Nganluong\Api\PaymentTypes;

use Payum\Core\Action\PaymentAwareAction;

abstract class GetPaymentMethodAction extends PaymentAwareAction
{
	const DEFAULT_PAYMENT_TYPE = PaymentTypes::TYPE_IMMEDIATE;

    /**
     * {@inheritDoc}
     *
     * @param $request GetPaymentMethod
     */
    public function execute($request)
    {
        if (!$this->supports($request)) {
            throw RequestNotSupportedException::createActionNotSupported($this, $request);
        }

        $model = ArrayObject::ensureArrayObject($request->getModel());

		$request->setInfo($this->getMethodCode($model));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
			$request instanceof GetPaymentMethod &&
			$request->getModel() instanceof \ArrayAccess
		;
    }

	/**
	* Gets payment method code from method name
	*
	* @param object $model
	*
	* @return array
	*/
	protected function getMethodCode($model)
	{
		$keywords = array(
			'visa' => 'VISA',
			'atm' => 'ATM_ONLINE',
			'nl' => 'NL',
			'ví' => 'NL',
			'ttvp' => 'TTVP',
		);

		$paymentMethodName = $this->getPaymentMethodName($model);
		$info = array();
		foreach($keywords as $key => $paymentMethod)
		{
			if ( strpos(strtolower($paymentMethodName), $key) !== false  )
			{
				$info['payment_method'] = $paymentMethod;
				break;
			}
		}

		if ( !isset($info['payment_method']) )
		{
			throw new \LogicException('No payment method supports.');
		}

		$info['payment_type'] = 1;

		return $info;
	}

	/**
	* Get human payment method name
	*
	* @param object $model
	*
	* @return string
	*/
	abstract protected function getPaymentMethodName($model);
}


<?php

namespace Ferdirn\Countries;

use Illuminate\Support\ServiceProvider;

/**
 * CountryListServiceProvider
 *
 */

class CountriesServiceProvider extends ServiceProvider {

	/**
	 * Indicates if loading of the provider is deferred.
	 *
	 * @var bool
	 */
	protected $defer = false;

        /**
        * Bootstrap the application.
        *
        * @return void
        */
        public function boot()
        {
            $this->package('ferdirn/laravel-id-countries');
        }

	/**
	 * Register everything.
	 *
	 * @return void
	 */
	public function register()
	{
	    $this->registerCountries();
	    $this->registerCommands();
	}

	/**
	 * Register the service provider.
	 *
	 * @return void
	 */
	public function registerCountries()
	{
	    $this->app->bind('countries', function($app)
	    {
	        return new Countries();
	    });
	}

	/**
	 * Register the artisan commands.
	 *
	 * @return void
	 */
	protected function registerCommands()
	{
	    $this->app['command.countries.migration'] = $this->app->share(function($app)
	    {
	        return new MigrationCommand($app);
	    });

	    $this->commands('command.countries.migration');
	}

	/**
	 * Get the services provided by the provider.
	 *
	 * @return array
	 */
	public function provides()
	{
		return array('countries');
	}
}


<?php

namespace FondOfSpryker\Client\AvailabilityAlert\Dependency\Client;

use Spryker\Shared\Kernel\Transfer\TransferInterface;

class AvailabilityAlertToZedRequestBridge implements AvailabilityAlertToZedRequestInterface
{
    /**
     * @var \Spryker\Client\ZedRequest\ZedRequestClientInterface
     */
    protected $zedRequestClient;

    /**
     * @param \Spryker\Client\Storage\StorageClientInterface $zedRequestClient
     */
    public function __construct($zedRequestClient)
    {
        $this->zedRequestClient = $zedRequestClient;
    }

    /**
     * @param string $url
     * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $object
     * @param int|null $timeoutInSeconds
     *
     * @return \Spryker\Shared\Kernel\Transfer\TransferInterface
     */
    public function call($url, TransferInterface $object, $timeoutInSeconds = null)
    {
        return $this->zedRequestClient->call($url, $object, $timeoutInSeconds);
    }
}


<?php
/**
 * This file is part of the EkiPayumNganluongBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Action;

use Payum\Core\Request\Notify;
use Payum\Core\Request\Sync;
use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\Exception\RequestNotSupportedException;

class NotifyAction extends PaymentAwareAction
{
    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Notify */
        RequestNotSupportedException::assertSupports($this, $request);

        $this->payment->execute(new Sync($request->getModel()));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Notify &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php

namespace AnrDaemon\Utility;

class Path
{
  /** Creates fixed pathinfo structure
  *
  * Meaning, "$dirname/$filename$extension" eq. rtrim($path, "\\/").
  *
  * Contrary to the {@see \pathinfo() pathinfo()}, all members of the structure always set.
  *
  * @param string $path The path to get info on.
  * @return array Fixed pathinfo structure.
  */
  public static function info($path)
  {
    $p = pathinfo($path);
    if(empty($p["filename"]))
    {
      $p["filename"] = $p["basename"];
      unset($p["extension"]);
    }
    if(!empty($p["extension"]))
    {
      $p["extension"] = ".{$p["extension"]}";
    }

    return $p + ["extension" => ""];
  }

  /** Path normalizer part examinator.
  * @internal
  * @throws \UnexpectedValueException if relative path is trying to escape above current directory, unless explicitly allowed.
  */
  protected static function examine($part, array &$array, $path_relative, $allow_escape = false)
  {
    if($part === '.')
    {
      return;
    }

    if($part !== '..')
    {
      $array[] = $part;
      return;
    }

    // $part == '..', handle escaping.
    $last = end($array);
    if($last === '..')
    { // Escaping is allowed and we're already on the run.
      $array[] = $part;
      return;
    }

    if($last !== false)
    { // $last element exists - move up the stack.
      array_pop($array);
      return;
    }

    if(!$path_relative)
    { // Path is not relative - skip updir.
      return;
    }

    if(!$allow_escape)
      throw new \UnexpectedValueException('Attempt to traverse outside the root directory.');

    $array[] = $part;
  }

  /** Normalize path string, removing '.'/'..'/empty components.
  *
  * Warning: This function is NOT intended to handle URL's ("//host/path")!
  * Please use {@see \parse_url() parse_url()} first.
  *
  * @param string $path The path to normalize.
  * @param bool $allow_escape Is the path relative? Defaults to autodetect. Paths declared explicitly relative get slightly different treatment.
  * @param string $directory_separator Output directory separator. Defaults to DIRECTORY_SEPARATOR.
  * @return string The normalized string.
  * @throws \UnexpectedValueException if relative path is trying to escape above current directory, unless explicitly allowed.
  */
  public static function normalize($path, $allow_escape = false, $directory_separator = DIRECTORY_SEPARATOR)
  {
    $path = (string)$path;
    if($path === '')
      return $path;

    $disk = null;
    $path_relative = false;

    // If path is not explicitly relative, test if it's an absolute and possibly Windows path
    // Convert first byte to uppercase.
    $char = ord($path[0]) & 0xdf;
    if($char & 0x80)
    { // Multibyte character - path is relative
      $path_relative = true;
    }
    // Windows disk prefix "{A..Z}:"
    elseif(strlen($path) > 1 && $char > 0x40 && $char < 0x5b && $path[1] === ':')
    {
      if(strlen($path) === 2)
        return $path;

      $disk = substr($path, 0, 2);
      $path = substr($path, 2);
    }

    if($path[0] !== "/" && $path[0] !== "\\")
    { // First byte is not a slash
      $path_relative = true;
    }

    $ta = [];
    $part = strtok($path, "/\\");
    while(false !== $part)
    {
      static::examine($part, $ta, $path_relative, $allow_escape);
      $part = strtok("/\\");
    }

    return $disk . ($path_relative ? '' : $directory_separator) . join($directory_separator, $ta);
  }
}


<?php

namespace FondOfSpryker\Yves\AvailabilityAlert\Form;

use Generated\Shared\Transfer\AvailabilityAlertSubscriptionRequestTransfer;
use Spryker\Yves\Kernel\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\NotBlank;

class SubscriptionForm extends AbstractType
{
    const FIELD_PRODUCT = AvailabilityAlertSubscriptionRequestTransfer::ID_PRODUCT_ABSTRACT;
    const FIELD_EMAIL = AvailabilityAlertSubscriptionRequestTransfer::EMAIL;

    /**
     * @return string
     */
    public function getBlockPrefix()
    {
        return 'availabilityAlertSubscriptionForm';
    }

    /**
     * @param \Symfony\Component\Form\FormBuilderInterface $builder
     * @param array $options
     *
     * @return void
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);

        $this->addEmailField($builder)
            ->addProductField($builder);
    }

    /**
     * @param \Symfony\Component\Form\FormBuilderInterface $builder
     *
     * @return $this
     */
    protected function addEmailField(FormBuilderInterface $builder)
    {
        $builder->add(self::FIELD_EMAIL, EmailType::class, [
            'label' => 'availability_alert.submit.email',
            'required' => true,
            'constraints' => [
                new NotBlank(),
            ],
        ]);

        return $this;
    }

    /**
     * @param \Symfony\Component\Form\FormBuilderInterface $builder
     *
     * @return $this
     */
    protected function addProductField(FormBuilderInterface $builder)
    {
        $builder->add(static::FIELD_PRODUCT, HiddenType::class, [
            'required' => true,
            'constraints' => [
                new NotBlank(),
            ],
        ]);

        return $this;
    }
}


<?php
//
// +---------------------------------------------------------------------+
// | CODE INC. SOURCE CODE                                               |
// +---------------------------------------------------------------------+
// | Copyright (c) 2017 - Code Inc. SAS - All Rights Reserved.           |
// | Visit https://www.codeinc.fr for more information about licensing.  |
// +---------------------------------------------------------------------+
// | NOTICE:  All information contained herein is, and remains the       |
// | property of Code Inc. SAS. The intellectual and technical concepts  |
// | contained herein are proprietary to Code Inc. SAS are protected by  |
// | trade secret or copyright law. Dissemination of this information or |
// | reproduction of this material  is strictly forbidden unless prior   |
// | written permission is obtained from Code Inc. SAS.                  |
// +---------------------------------------------------------------------+
//
// Author:   Joan Fabrégat <joan@codeinc.fr>
// Date:     02/03/2018
// Time:     10:45
// Project:  SessionManager
//
declare(strict_types = 1);
namespace CodeInc\SessionManager;
use CodeInc\SessionManager\Exceptions\NoSessionStartedException;
use CodeInc\SessionManager\Exceptions\SessionManagerException;
use CodeInc\SessionManager\Handlers\HandlerInterface;
use HansOtt\PSR7Cookies\SetCookie;
use Psr\Http\Message\ServerRequestInterface;

/**
 * Class SessionManager
 *
 * @package CodeInc\Session
 * @author Joan Fabrégat <joan@codeinc.fr>
 */
class SessionManager
{
    public const DEFAULT_NAME = "SID";
    public const DEFAULT_EXPIRE = 60;

    /**
     * Session handler
     *
     * @var HandlerInterface
     */
    private $handler;

    /**
     * Session data holder
     *
     * @see SessionManager::getDataHolder()
     * @var SessionDataHolder|null
     */
    private $dataHolder;

    /**
     * Session name
     *
     * @var string
     */
    private $name;

    /**
     * Session lifespan in minutes.
     *
     * @var int
     */
    private $expire;

    /**
     * Session cookie host
     *
     * @var string|null
     */
    private $cookieHost;

    /**
     * Session cookie secure
     *
     * @var bool
     */
    private $cookieSecure = false;

    /**
     * Session cookie path
     *
     * @var string|null
     */
    private $cookiePath;

    /**
     * Verifies if the session cookie must be HTTP only.
     *
     * @var bool
     */
    private $cookieHttpOnly = true;

    /**
     * Verifies if the client IP address needs to be validated.
     *
     * @var bool
     */
    private $validateClientIp = false;

    /**
     * SessionManager constructor.
     *
     * @param HandlerInterface $handler
     * @param null|string $name
     * @param int|null $expire
     */
    public function __construct(HandlerInterface $handler, ?string $name = null,
        ?int $expire = null)
    {
        $this->handler = $handler;
        $this->name = $name ?? self::DEFAULT_NAME;
        $this->expire = $expire ?? self::DEFAULT_EXPIRE;
    }

    /**
     * Destructor. Saves the session data.
     *
     * @throws NoSessionStartedException
     */
    public function __destruct()
    {
        if ($this->isStarted()) {
            $dataHolder = $this->getDataHolder();

            // saving the session
            $dataHolder->updateLastRequestTime();
            $this->getHandler()->write($dataHolder->getId(), $dataHolder->getData());

            // one time on 100 we delete the expired sessions
            if (rand(1, 100) == 50) {
                $this->getHandler()->cleanup($this->getExpire() * 60);
            }
        }
    }

    /**
     * @return HandlerInterface
     */
    public function getHandler():HandlerInterface
    {
        return $this->handler;
    }

    /**
     * @param ServerRequestInterface $request
     * @return SessionDataHolder
     * @throws SessionManagerException
     */
    public function start(ServerRequestInterface $request):SessionDataHolder
    {
        if ($this->isStarted()) {
            throw new SessionManagerException(
                "A session is already started",
                $this
            );
        }

        try {
            // if the session exists, loading it!
            if (isset($request->getCookieParams()[$this->getName()])) {
                $id = $request->getCookieParams()[$this->getName()];
                // the session is not valid = we delete the previous one and create a new one.
                if (($data = $this->getHandler()->read($id)) !== null) {
                    $this->dataHolder = new SessionDataHolder($this, $id, $data);
                    // if the session is invalid, we destroy the previous one and create a new one
                    if (!$this->isSessionValid($this->dataHolder, $request)) {
                        $this->getHandler()->destroy($id);
                        $this->dataHolder = SessionDataHolder::factory($this, $request);
                    }
                }

                // if the session can not be loaded, we create a new one
                else {
                    $this->getHandler()->destroy($id);
                    $this->dataHolder = SessionDataHolder::factory($this, $request);
                }
            }

            // else creating the session
            else {
                $this->dataHolder = SessionDataHolder::factory($this, $request);
            }

            return $this->dataHolder;
        }
        catch (\Throwable $exception) {
            throw new SessionManagerException(
                "Error while starting the session",
                $this, null, $exception
            );
        }
    }

    /**
     * Verifies if a session is valid
     *
     * @param SessionDataHolder $session
     * @param ServerRequestInterface $request
     * @return bool
     */
    private function isSessionValid(SessionDataHolder $session, ServerRequestInterface $request):bool
    {
        // if the session is expired
        if (($lastReq = $session->getLastRequestTime())
            && ($lastReq + $this->getExpire() * 60) < time())
        {
            return false;
        }

        // if the client IP changed
        if ($this->getValidateClientIp()
            && ($clientIp = $session->getClientIp())
            && isset($request->getServerParams()['REMOTE_ADDR'])
            && $clientIp != $request->getServerParams()['REMOTE_ADDR'])
        {
            return false;
        }

        return true;
    }

    /**
     * Returns the session cookie.
     *
     * @return SetCookie|null
     * @throws SessionManagerException
     */
    public function getSessionCookie():?SetCookie
    {
        try {
            // envoie du cookie de session
            if ($this->isStarted()) {
                return new SetCookie(
                    $this->getName(),
                    $this->getDataHolder()->getId(),
                    (time() + $this->getExpire() * 60),
                    $this->getCookiePath() ?? '/',
                    $this->getCookieHost() ?? '',
                    $this->getCookieSecure(),
                    $this->isCookieHttpOnly()
                );
            }

            // sinon destruction du cookie de session
            else {
                return SetCookie::thatDeletesCookie($this->getName());
            }
        }
        catch (\Throwable $exception) {
            throw new SessionManagerException(
                "Error while preparing the session cookie",
                $this, null, $exception
            );
        }
    }

    /**
     * Stops the session. All session data are destroyed in memory and on the
     * storage unit through the handler.
     *
     * @throws NoSessionStartedException
     */
    public function stop():void
    {
        if ($this->isStarted()) {
            $this->getHandler()->destroy($this->getDataHolder()->getId());
            $this->dataHolder = null;
        }
    }

    /**
     * Verifies if the session is started.
     *
     * @return bool
     */
    public function isStarted():bool
    {
        return $this->dataHolder instanceof SessionDataHolder;
    }

    /**
     * Returns the current session data holder.
     *
     * @return SessionDataHolder
     * @throws NoSessionStartedException
     */
    public function getDataHolder():SessionDataHolder
    {
        if (!$this->isStarted()) {
            throw new NoSessionStartedException($this);
        }
        return $this->dataHolder;
    }

    /**
     * @param string $name
     */
    public function setName(string $name):void
    {
        $this->name = $name;
    }

    /**
     * @return string
     */
    public function getName():string
    {
        return $this->name;
    }

    /**
     * @param int $expire
     */
    public function setExpire(int $expire):void
    {
        $this->expire = $expire;
    }

    /**
     * @return int
     */
    public function getExpire():int
    {
        return $this->expire;
    }

    /**
     * @param null|string $cookieHost
     */
    public function setCookieHost(?string $cookieHost):void
    {
        $this->cookieHost = $cookieHost;
    }

    /**
     * @return null|string
     */
    public function getCookieHost():?string
    {
        return $this->cookieHost;
    }

    /**
     * @param bool|null $cookieSecure
     */
    public function setCookieSecure(?bool $cookieSecure):void
    {
        $this->cookieSecure = $cookieSecure;
    }

    /**
     * @return bool|null
     */
    public function getCookieSecure():?bool
    {
        return $this->cookieSecure;
    }

    /**
     * @param null|string $cookiePath
     */
    public function setCookiePath(?string $cookiePath):void
    {
        $this->cookiePath = $cookiePath;
    }

    /**
     * @param bool $cookieHttpOnly
     */
    public function setCookieHttpOnly(bool $cookieHttpOnly):void
    {
        $this->cookieHttpOnly = $cookieHttpOnly;
    }

    /**
     * @return bool
     */
    public function isCookieHttpOnly():bool
    {
        return $this->cookieHttpOnly;
    }

    /**
     * @return null|string
     */
    public function getCookiePath():?string
    {
        return $this->cookiePath;
    }

    /**
     * @param bool $validateClientIp
     */
    public function setValidateClientIp(bool $validateClientIp):void
    {
        $this->validateClientIp = $validateClientIp;
    }

    /**
     * @return bool
     */
    public function getValidateClientIp():bool
    {
        return $this->validateClientIp;
    }
}


<?php

namespace FondOfSpryker\Zed\AvailabilityAlert;

use FondOfSpryker\Zed\AvailabilityAlert\Dependency\Facade\AvailabilityAlertToLocaleBridge;
use FondOfSpryker\Zed\AvailabilityAlert\Dependency\Facade\AvailabilityAlertToMailBridge;
use FondOfSpryker\Zed\AvailabilityAlert\Dependency\Facade\AvailabilityAlertToProductBridge;
use FondOfSpryker\Zed\AvailabilityAlert\Dependency\Facade\AvailabilityAlertToStoreBridge;
use Spryker\Zed\Kernel\AbstractBundleDependencyProvider;
use Spryker\Zed\Kernel\Container;

class AvailabilityAlertDependencyProvider extends AbstractBundleDependencyProvider
{
    const FACADE_LOCALE = 'FACADE_LOCALE';
    const FACADE_MAIL = 'FACADE_MAIL';
    const FACADE_AVAILABILITY = 'FACADE_AVAILABILITY';
    const FACADE_PRODUCT = 'FACADE_PRODUCT';
    const FACADE_STORE = 'FACADE_STORE';

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    public function provideBusinessLayerDependencies(Container $container)
    {
        $container = $this->addMailFacade($container);
        $container = $this->addAvailabilityFacade($container);
        $container = $this->addProductFacade($container);

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    public function provideCommunicationLayerDependencies(Container $container)
    {
        $container = $this->addLocaleFacade($container);
        $container = $this->addStoreFacade($container);

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addProductFacade(Container $container): Container
    {
        $container[static::FACADE_PRODUCT] = function (Container $container) {
            return new AvailabilityAlertToProductBridge($container->getLocator()->product()->facade());
        };

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addMailFacade(Container $container)
    {
        $container[static::FACADE_MAIL] = function (Container $container) {
            return new AvailabilityAlertToMailBridge($container->getLocator()->mail()->facade());
        };

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addLocaleFacade(Container $container)
    {
        $container[static::FACADE_LOCALE] = function (Container $container) {
            return new AvailabilityAlertToLocaleBridge($container->getLocator()->locale()->facade());
        };

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addStoreFacade(Container $container)
    {
        $container[static::FACADE_STORE] = function (Container $container) {
            return new AvailabilityAlertToStoreBridge($container->getLocator()->store()->facade());
        };

        return $container;
    }

    /**
     * @param \Spryker\Zed\Kernel\Container $container
     *
     * @return \Spryker\Zed\Kernel\Container
     */
    protected function addAvailabilityFacade(Container $container)
    {
        $container[static::FACADE_AVAILABILITY] = function (Container $container) {
            return $container->getLocator()->availability()->facade();
        };

        return $container;
    }
}


<?php

namespace FondOfSpryker\Yves\AvailabilityAlert\Plugin\Provider;

use Silex\Application;
use SprykerShop\Yves\ShopApplication\Plugin\Provider\AbstractYvesControllerProvider;

class AvailabilityAlertControllerProvider extends AbstractYvesControllerProvider
{
    const ROUTE_AVAILABILITY_ALERT_SUBMIT = 'availability-alert/submit';

    const ID_ABSTRACT_PRODUCT_REGEX = '[1-9][0-9]*';

    /**
     * @param \Silex\Application $app
     *
     * @return void
     */
    protected function defineControllers(Application $app)
    {
        $allowedLocalesPattern = $this->getAllowedLocalesPattern();

        $this->createController('/{availabilityAlert}/submit/{idProductAbstract}', static::ROUTE_AVAILABILITY_ALERT_SUBMIT, 'AvailabilityAlert', 'Submit', 'index')
            ->assert('availabilityAlert', $allowedLocalesPattern . 'availability-alert|availability-alert')
            ->value('availabilityAlert', 'availability-alert')
            ->assert('idProductAbstract', static::ID_ABSTRACT_PRODUCT_REGEX);
    }
}


<?php
/**
 * This file is part of the EkiPayumNganluong package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Bridge\Symfony;

use Payum\Bundle\PayumBundle\DependencyInjection\Factory\Payment\AbstractPaymentFactory;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

abstract class BasePaymentFactory extends AbstractPaymentFactory
{
	protected $actionPrefixClass = 'Eki\\Payum\\Nganluong\\Action\\';

    protected function paymentAddAction(
		ContainerBuilder $container,
		Definition $paymentDefinition,
		$actionName,
		$actionPrefixClass,
		$contextName,
		array $arguments = array(),
		$public = false
	)
	{
		$actionPrefixClass = $actionPrefixClass == null ? $this->$actionPrefixClass : $actionPrefixClass;

        $actionDefinition = new Definition($actionPrefixClass.$actionName.'Action');
		$actionDefinition->setPublic((bool)$public);
		foreach($arguments as $argument)
		{
	        $actionDefinition->addArgument($argument);
		}
        $actionId = "payum." . $this->getName() . ".action." . $this->from_camel_case($actionName);
        $container->setDefinition($actionId, $actionDefinition);

        $paymentDefinition->addMethodCall('addAction', array(new Reference($actionId)));
	}

	private function from_camel_case($input)
	{
	  preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
	  $ret = $matches[0];
	  foreach ($ret as &$match) {
	    $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
	  }
	  return implode('_', $ret);
	}

    /**
     * {@inheritDoc}
     */
    public function addConfiguration(ArrayNodeDefinition $builder)
    {
        parent::addConfiguration($builder);

        $builder->children()
            ->scalarNode('merchant_id')->isRequired()->cannotBeEmpty()->end()
            ->scalarNode('merchant_password')->isRequired()->cannotBeEmpty()->end()
            ->scalarNode('receiver_email')->isRequired()->cannotBeEmpty()->end()
            ->booleanNode('sandbox')->defaultTrue()->end()
            ->scalarNode('sandbox_url')->end()
        ->end();
    }

    /**
     * {@inheritDoc}
     */
    protected function addApis(Definition $paymentDefinition, ContainerBuilder $container, $contextName, array $config)
    {
		$options = array(
            'merchant_id' => $config['merchant_id'],
            'merchant_password' => $config['merchant_password'],
            'receiver_email' => $config['receiver_email'],
            'sandbox' => $config['sandbox']
		);
		if ( isset($config['sandbox_url']) )
		{
			$options['sandbox_url'] = $config['sandbox_url'];
		}

        $apiDefinition = new DefinitionDecorator('eki.payum.nganluong.api.prototype');
        $apiDefinition->replaceArgument(0, $options);
        $apiDefinition->setPublic(true);
        $apiId = 'eki.payum.context.'.$contextName.'.api';
        $container->setDefinition($apiId, $apiDefinition);
        $paymentDefinition->addMethodCall('addApi', array(new Reference($apiId)));
    }

    /**
     * {@inheritDoc}
     */
    protected function addActions(Definition $paymentDefinition, ContainerBuilder $container, $contextName, array $config)
    {
		if ( isset($config['sandbox']) && $config['sandbox'] != false )
		{
	        $loggerDefinition = new Definition();
	        $loggerDefinition->setClass('Eki\Payum\Nganluong\Action\LoggerAwareAction');
			$loggerDefinition->addMethodCall(
				'setLogger',
				array(new Reference('logger'))
			);
			$loggerActionId = 'payum.'.$contextName.'.nganluong.action.logger_aware';
	        $container->setDefinition($loggerActionId, $loggerDefinition);

            $paymentDefinition->addMethodCall(
                'addAction',
                array(new Reference($loggerActionId), $forcePrepend = true)
            );
		}
    }
}


<?php
/**
 * This file is part of the EkiPayum package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong;

use Eki\Payum\Nganluong\Action\CaptureOnsiteAction;
use Eki\Payum\Nganluong\Action\FillOrderDetailsAction;
use Eki\Payum\Nganluong\Action\StatusAction;

use Eki\Payum\Nganluong\Action\Api\SetExpressCheckoutAction;
use Eki\Payum\Nganluong\Action\Api\GetTransactionDetailsAction;

use Payum\Core\Action\ExecuteSameRequestWithModelDetailsAction;
use Payum\Core\Action\GetHttpRequestAction;
use Payum\Core\Payment;
use Payum\Core\Extension\EndlessCycleDetectorExtension;

abstract class OnsitePaymentFactory
{
    /**
     * @param Api $api
     *
     * @return \Payum\Core\Payment
     */
    public static function create(Api $api)
    {
        $payment = new Payment;

        $payment->addApi($api);

        $payment->addExtension(new EndlessCycleDetectorExtension);

        $payment->addAction(new SetExpressCheckoutAction);
        $payment->addAction(new GetTransactionDetailsAction);

        $payment->addAction(new CaptureOnsiteAction);
        $payment->addAction(new FillOrderDetailsAction);
        $payment->addAction(new StatusAction);
        $payment->addAction(new ExecuteSameRequestWithModelDetailsAction);
        $payment->addAction(new GetHttpRequestAction);

        return $payment;
    }

    /**
     */
    private  function __construct()
    {
    }
}


<?php
/**
 * This file is part of the EkiPayumNganluongBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Action\ATMOnline;

use Eki\Payum\Nganluong\Action\CaptureAction as BaseCaptureAction;
use Eki\Payum\Nganluong\Request\Log;
use Eki\Payum\Nganluong\Request\ATMOnline\DetermineBank;

use Payum\Core\Exception\RequestNotSupportedException;

class CaptureAction extends BaseCaptureAction
{
	/**
	* Process payment info (method, type, bakn, ...)
	* )
	* @param mixed $request
	* @param mixed $model
	*
	* $return void
	*/
	protected function processPaymentInfo($request, $model)
	{
		$this->payment->execute(new Log('Payment method is ATM_ONLINE. It must obtain bank code first.', $this));
		if ( false == $model->validateNotEmpty(array('bank_code'), false) )
		{
			$this->payment->execute(new Log('Get bank code...', $this));
			try
			{
	            $this->payment->execute($bankRequest = new DetermineBank);
				$bank = $bankRequest->determine();

				$model['bank_code'] = $bank->getCode();
            }
			catch (RequestNotSupportedException $e)
			{
                throw new \LogicException('Bank code has to be set explicitly or there has to be an action that supports DetermineBank request.');
            }
		}
	}
}


<?php

namespace Ferdirn\Countries;

/**
 * CountryList
 *
 */
class Countries extends \Eloquent {

	/**
	 * @var string
	 * Countries data.
	 */
	protected $countries;

	/**
	 * @var string
	 * The table for the countries in the database, is "countries" by default.
	 */
	protected $table;

    /**
     * Constructor.
     *
     * @return void
     */
    public function __construct()
    {
       $this->table = \Config::get('laravel-id-countries::table_name');
    }

    /**
     * Get the countries from the JSON file, if it hasn't already been loaded.
     *
     * @return array
     */
    protected function getCountries()
    {
        //Get the countries from the JSON file
        if (sizeof($this->countries) == 0){
            $this->countries = json_decode(file_get_contents(__DIR__ . '/Models/countries.json'), true);
        }

        //Return the countries
        return $this->countries;
    }

	/**
	 * Returns one country
	 *
	 * @param string $id The country id
     *
	 * @return array
	 */
	public function getOne($id)
	{
        $countries = $this->getCountries();
		return $countries[$id];
	}

	/**
	 * Returns a list of countries
	 *
	 * @param string sort
	 *
	 * @return array
	 */
	public function getList($sort = null)
	{
	    //Get the countries list
	    $countries = $this->getCountries();

	    //Sorting
	    $validSorts = array(
	        'name',
	        'fullname',
	        'iso_3166_2',
	        'iso_3166_3',
	        'capital',
	        'citizenship',
	        'currency',
	        'currency_code',
	        'calling_code'
        );

	    if (!is_null($sort) && in_array($sort, $validSorts)){
	        uasort($countries, function($a, $b) use ($sort) {
	            if (!isset($a[$sort]) && !isset($b[$sort])){
	                return 0;
	            } elseif (!isset($a[$sort])){
	                return -1;
	            } elseif (!isset($b[$sort])){
	                return 1;
	            } else {
	                return strcasecmp($a[$sort], $b[$sort]);
	            }
	        });
	    }

	    //Return the countries
		return $countries;
	}
}


<?php
/**
 * This file is part of the EkiSyliusPayumBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Bridge\Sylius;

use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\Exception\RequestNotSupportedException;
use Sylius\Component\Payment\Model\PaymentInterface;

use Eki\Payum\Nganluong\Request\Api\GetPaymentMethod;
use Eki\Payum\Nganluong\Api\PaymentTypes;

class GetPaymentMethodAction extends PaymentAwareAction
{
	const DEFAULT_PAYMENT_TYPE = PaymentTypes::TYPE_IMMEDIATE;

    /**
     * {@inheritDoc}
     *
     * @param $request GetPaymentMethod
     */
    public function execute($request)
    {
        if (!$this->supports($request)) {
            throw RequestNotSupportedException::createActionNotSupported($this, $request);
        }

        /** @var $payment PaymentInterface */
        $payment = $request->getModel();

		$info = array();
		$info['payment_type'] = self::DEFAULT_PAYMENT_TYPE;
		$info['payment_method'] = $this->getMethodCode(strtolower($payment->getMethod()->getName()));

		$request->setInfo($info);
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetPaymentMethod &&
            $request->getModel() instanceof PaymentInterface
        ;
    }

	/**
	* Gets payment method code
	*
	* @param string $name
	*
	* @return string|null
	*/
	protected function getMethodCode($name)
	{
		$mappings = array(
			'nganluong_visa' => 'VISA',
			'nganluong_atm' => 'ATM_ONLINE',
			'nganluong_ttvp' => 'TTVP',
			'nganluong_nl' => 'NL',
		);

		if ( in_array( $name, array_keys($mappings) ) )
		{
			return $mappings[$name];
		}
	}
}


<?php
/**
 * This file is part of the EkiSyliusPayumBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Bridge\Sylius;

use Doctrine\Common\Persistence\ObjectManager;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\Notify;
use Payum\Core\Request\Sync;
use SM\Factory\FactoryInterface;
use Sylius\Bundle\PayumBundle\Payum\Action\AbstractPaymentStateAwareAction;
use Sylius\Bundle\PayumBundle\Payum\Request\GetStatus;
use Sylius\Component\Payment\Model\PaymentInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class NotifyOrderAction extends AbstractPaymentStateAwareAction
{
    /**
     * @var EventDispatcherInterface
     */
    protected $eventDispatcher;

    /**
     * @var ObjectManager
     */
    protected $objectManager;

    /**
     * @param EventDispatcherInterface $eventDispatcher
     * @param ObjectManager            $objectManager
     * @param FactoryInterface         $factory
     */
    public function __construct(EventDispatcherInterface $eventDispatcher, ObjectManager $objectManager, FactoryInterface $factory)
    {
        parent::__construct($factory);

        $this->eventDispatcher = $eventDispatcher;
        $this->objectManager   = $objectManager;
    }

    /**
     * {@inheritDoc}
     *
     * @param $request Notify
     */
    public function execute($request)
    {
        if (!$this->supports($request)) {
            throw RequestNotSupportedException::createActionNotSupported($this, $request);
        }

        /** @var $payment PaymentInterface */
        $payment = $request->getModel();

        $this->payment->execute(new Sync($payment));

        $status = new GetStatus($payment);
        $this->payment->execute($status);

        $nextState = $status->getValue();

        $this->updatePaymentState($payment, $nextState);

        $this->objectManager->flush();
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Notify &&
            $request->getToken() &&
            $request->getModel() instanceof PaymentInterface
        ;
    }
}


<?php
/**
 * This file is part of the EkiPayumNganluongBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Action\ATMOnline;

use Eki\Payum\Nganluong\Model\BankInterface;
use Eki\Payum\Nganluong\Request\ATMOnline\DetermineBank;

use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\Bridge\Symfony\Reply\HttpResponse;
use Payum\Core\Exception\LogicException;
use Payum\Core\Exception\RequestNotSupportedException;

use Payum\Core\Request\RenderTemplate;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class DetermineBankAction extends PaymentAwareAction
{
    /**
     * @var FormFactoryInterface
     */
    protected $formFactory;

    /**
     * @var Request
     */
    protected $httpRequest;

    /**
     * @var string
     */
    protected $templateName;

    /**
     * @var string
     */
    protected $formName;

    /**
     * @param FormFactoryInterface $formFactory
     * @param string $templateName
     * @param string $formName
     */
    public function __construct(FormFactoryInterface $formFactory, $templateName, $formName = null)
    {
        $this->formFactory = $formFactory;
        $this->templateName = $templateName;
		$this->formName = $formName;
    }

    /**
     * @param Request $request
     */
    public function setRequest(Request $request = null)
    {
        $this->httpRequest = $request;
    }

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request DetermineBank */
        if (!$this->supports($request)) {
            throw RequestNotSupportedException::createActionNotSupported($this, $request);
        }
        if (!$this->httpRequest) {
            throw new LogicException('The action can be run only when http request is set.');
        }

        $form = $this->createBankListForm();

        $form->handleRequest($this->httpRequest);
        if ($form->isSubmitted()) {
            /** @var BankInterface $bank */
            $bank = $form->getData();

            if ($form->isValid()) {
                $request->set($bank);

                return;
             }
        }

        $renderTemplate = new RenderTemplate($this->templateName, array(
            'form' => $form->createView()
        ));
        $this->payment->execute($renderTemplate);

        throw new HttpResponse(new Response($renderTemplate->getResult(), 200, array(
            'Cache-Control' => 'no-store, no-cache, max-age=0, post-check=0, pre-check=0',
            'Pragma' => 'no-cache',
        )));
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return $request instanceof DetermineBank;
    }

    /**
     * @return FormInterface
     */
    protected function createBankListForm()
    {
        return $this->formFactory->create( null !== $this->formName ? $this->formName : 'eki_nganluong_bank_list' );
    }
}


<?php
/** URL handling class.
*
* @version SVN: $Id: Url.php 909 2018-10-17 13:21:08Z anrdaemon $
*/

namespace AnrDaemon\Net;

/** A class to simplify handling the various URL's
*
* The class is a read-only collection, the only way to modify its contents
* is to create a new instance of the class.
*
* URL parts can be accessed as properties (`$url->path`), query parts (beside
* obvious `$url->query['param']`) can also be accessed as array indices
* (`$url['param']`) for convenience.
*
* When parsing the URI or setting parts, empty values are stripped.
*
* In case you want to create a website self-reference URL, the named
* constructor {@see \AnrDaemon\Net\Url::fromHttp self::fromHttp} is provided.
*
* It will try to populate scheme/host/port/path/query parts from information
* available in $_SERVER array.
*
* Warning: PHP compat: PHP ({@see \parse_str parse_str()}) converts certain characters in request variable names.
* See Note after Example 3 on http://php.net/variables.external#example-88
*
* @property-read string $scheme Treatment of some well-known schemes (like http or ldap) is enhanced.
* @property-read string $user
* @property-read string $pass
* @property-read string $host The IDN hosts are decoded.
* @property-read int $port The port is always converted to integer.
* @property-read string $path Path, always decoded, like in `$_SERVER['DOCUMENT_URI']`.
* @property-read array $query Part after the question mark "?".
* @property-read string $fragment Part after the hashmark "#".
*/
class Url
implements \IteratorAggregate, \ArrayAccess, \Countable
{
  /**
  * @var array $defaultPorts The list of well-known schemes and associated ports.
  * @source 1 16 The current list of well-known schemes:
  */
  protected static $defaultPorts = array(
    'ftp' => 21,
    'ftps' => 990,
    'gopher' => 70,
    'http'  => 80,
    'https' => 443,
    'imap' => 143,
    'imaps' => 993,
    'ldap' => 389,
    'ldaps' => 636,
    'nntp' => 119,
    'nntps' => 563,
    'pop3' => 110,
    'pop3s' => 995,
    'ssh' => 22,
    'telnet' => 23,
    'telnets' => 992,
  );

  /**
  * @var array $params Internal array holding the URI parts.
  * @source 1 8 Parts list:
  */
  protected $params = array(
    'scheme' => null, // - e.g. http
    'user' => null, //
    'pass' => null, //
    'host' => null, //
    'port' => null, //
    'path' => null, //
    'query' => null, // - after the question mark ?
    'fragment' => null, // - after the hashmark #
  );

  /** @var string Cached representation of this object. */
  protected $uri;

  /** @internal Parse URL and throw exception on error.
  * @param string $url
  * @return array
  * @see \parse_url()
  */
  protected function _parse_url($url)
  {
    // TODO: Correctly handle mailto: scheme https://3v4l.org/S0AIa mailto://user@example.org
    $parts = parse_url($url);
    if($parts === false)
      throw new \InvalidArgumentException("Provided argument can not be parsed as valid URL.");

    return $parts;
  }

  /** @internal Parse query string and return resulting array.
  *
  * If input is not a string, the input returned unmodified.
  *
  * @param string $string
  * @return array
  * @see \parse_str()
  */
  protected function _parse_str($string)
  {
    if(is_array($string))
      return $string;
    // TODO:query strtok($query, ini_get('arg_separator.input'));
    parse_str($string, $query);
    return $query;
  }

  /** @internal Recursive ksort
  * @param array &$array
  * @return void
  * @see \ksort()
  */
  protected function _rksort(&$array)
  {
    if(is_array($array))
    {
      ksort($array);
      array_walk($array, array($this, __FUNCTION__));
    }
  }

  /** Creates Url instance from HTTP request metadata, such as $_SERVER[REQUEST_*] and $_SERVER[HTTP_*] variables.
  *
  * Function uses data available in the request environment to construct the so-called self-reference.
  *
  * The order in which environment is processed is as follows:
  *
  *  1. X-Forwarded-* headers, if trusted.
  *  2. The entire REQUEST_URI variable as set by SAPI.
  *  3. REQUEST_SCHEME / SERVER_NAME / SERVER_PORT variables from SAPI.
  *  4. The Host header in case host part was not set yet.
  *
  * If $trust_x_forwarded_headers is true (the default), the following headers are considered:
  *
  *  - X-Forwarded-Proto - original protocol the request received with (f.e. https);
  *  - X-Forwarded-Port - original receiving port;
  *  - X-Forwarded-Host - host (and possible port, if not set by X-Forwarded-Port) the original request received for.
  *
  * Warning: It is stronly recommended to configure calling webserver to override X-Forwarded-* headers an application
  * should not trust.
  *
  * Warning: Application should receive an already sanitized environment it could rely upon.
  *
  * @param array $override An array of parts to override. {@see \AnrDaemon\Net\Url::setParts() self::setParts()}
  * @param bool $trust_x_forwarded_headers To trust the X-Forwarded-{Host,Port,Proto,etc.} headers or not.
  * @return Url A new class instance.
  */
  public static function fromHttp(array $overrides = [], $trust_x_forwarded_headers = true)
  {
    $self = new static("");
    $parts = [];

    if($trust_x_forwarded_headers)
    {
      foreach(array(
        'scheme' => "HTTP_X_FORWARDED_PROTO",
        'port' => "HTTP_X_FORWARDED_PORT",
      ) as $key => $header)
      {
        if(!empty($_SERVER[$header]))
        {
          $parts += [$key => $_SERVER[$header]];
        }
      }

      if(!empty($_SERVER["HTTP_X_FORWARDED_HOST"]))
      {
        $parts += $self->_parse_url("//{$_SERVER["HTTP_X_FORWARDED_HOST"]}");
      }
    }

    if(!empty($_SERVER["REQUEST_URI"]))
    {
      $parts += $self->_parse_url($_SERVER["REQUEST_URI"]);
    }

    foreach(array(
      'scheme' => "REQUEST_SCHEME",
      'host' => "SERVER_NAME",
      'port' => "SERVER_PORT",
    ) as $key => $header)
    {
      if(!isset($parts[$key]) && !empty($_SERVER[$header]))
      {
        $parts += [$key => $_SERVER[$header]];
      }
    }

    /** Parse Host: header as host[:port] */
    if(empty($parts['host']) && !empty($_SERVER['HTTP_HOST']))
    {
      $parts += $self->_parse_url("//{$_SERVER['HTTP_HOST']}");
    }

    if(!empty($parts['host']))
    {
      $parts['host'] = idn_to_utf8($parts['host'], 0, INTL_IDNA_VARIANT_UTS46);
    }

    return $self->setParts($overrides + $parts);
  }

  /** Parse an URL into replacement parts and create a new class instance using them
  *
  * Takes apart the `$url` and uses its parts to call {@see \AnrDaemon\Net\Url::setParts() self::setParts()}.
  *
  * The user, password and fragment fields are url-decoded.
  *
  * The IDN hostnames are decoded.
  *
  * The path is url-decoded, except for encoded "/"(%2F) character.
  *
  * The query string is decoded into an array by the extension of using
  * {@see \AnrDaemon\Net\Url::setParts() self::setParts()} to compose a new class instance.
  *
  * Note: May not parse all URL's in a desirable way.
  * See f.e. https://3v4l.org/BPsaa for mailto: URI's
  *
  * @see https://tools.ietf.org/html/rfc3986 [RFC3986]
  * @see \parse_url()
  * @see \parse_str()
  *
  * @uses \AnrDaemon\Net\Url::setParts() to construct resulting object.
  *
  * @param string $url An URL to parse.
  * @return Url A new class instance with corresponding parts replaced.
  */
  public function parse($url)
  {
    $parts = $this->_parse_url($url);

    foreach(array('user', 'pass', 'fragment') as $part)
      if(isset($parts[$part]))
        $parts[$part] = urldecode($parts[$part]);

    if(isset($parts['host']))
      $parts['host'] = idn_to_utf8($parts['host']);

    if(isset($parts['path']))
      $parts['path'] = rawurldecode(str_ireplace('%2F', '%252F', $parts['path']));

    return $this->setParts($parts);
  }

  /** Create a new instance of the class by replacing parts in the current instance
  *
  * Note: This is a replacement, not merge; especially in case of a `query` part.
  *
  * Note: The `query` part is always decoded into an array.
  *
  * @param array $parts A set of parts to replace. Uses the same names parse_url uses.
  * @return \AnrDaemon\Net\Url A new class instance with corresponding parts replaced.
  */
  public function setParts(array $parts)
  {
    /** Filter input array */
    $parts = array_intersect_key($parts, $this->params);

    /** Force port to be numeric.
    *
    * If it would fail to convert (converts to zero), we will strip it.
    */
    if(isset($parts['port']))
      $parts['port'] = (int)$parts['port'];

    /** Convert query string to ksort()'ed array */
    if(isset($parts['query']))
    {
      $query = $this->_parse_str($parts['query']);
      $this->_rksort($query);
      $parts['query'] = $query;
    }

    /** Reset empty replacement parts to null
    *
    * This simplifies later checks for existence of URL parts.
    */
    array_walk(
      $parts,
      function(&$part, $key)
      {
        if(is_string($part))
        { /** Use strlen() instead of empty() to account for possible "0" values
          *
          * Valid case for (f.e.) user/pass parts.
          */
          $part = strlen($part) ? $part : null;
        }
        else
        {
          $part = $part ?: null;
        }
      }
    );

    $self = clone $this;
    // Keep URL parts in the same order at all times.
    $self->params = array_replace($this->params, $parts);
    return $self;
  }

// Magic!

  /** Create a representation of an URL.
  *
  * Without parameters, the class creates an "empty" URL.
  *
  * If base URL is specified, it will be used as template to fill parts.
  *
  * Hint: Provide an empty `$query` array to override any potential base URL query part.
  *
  * @param ?string $baseUrl An optional base URL to set defaults from.
  * @param ?array $query An optional query key-value pairs.
  */
  public function __construct($baseUrl = null, array $query = null)
  {
    if(!isset($baseUrl) || $baseUrl === '')
      return;

    $self = $this->parse($baseUrl);

    if(is_array($query))
    {
      $self = $self->setParts(['query' => $query]);
    }

    $this->params = $self->params;
  }

  /** @internal */
  public function __clone()
  {
    $this->uri = null;
  }

  /** @internal */
  public function __get($index)
  {
    return $this->params[$index];
  }

  /** @internal */
  public function __isset($index)
  {
    return isset($this->params[$index]);
  }

  /** Converts URL to a string representation.
  *
  * If URI scheme is specified, some well-known schemes are considered
  * and default port number is omitted from the resulting URI.
  *
  * @return string an URL-encoded string representation of the object.
  */
  public function __toString()
  {
    if($this->uri)
      return $this->uri;

    $parts = $this->params;
    $result = '';

    if(isset($parts['scheme']))
      $result .= $parts['scheme'] . ":";

    if(isset($parts['host']))
    {
      $result .= "//";

      if(isset($parts['user']))
      {
        $result .= rawurlencode($parts['user']);

        if(isset($parts['pass']))
          $result .= ":" . rawurlencode($parts['pass']);

        $result .= "@";
      }

      $result .= idn_to_ascii($parts['host']);

      if(isset($parts['port'], $parts['scheme'], self::$defaultPorts[$parts['scheme']]))
        if($parts['port'] == self::$defaultPorts[$parts['scheme']])
          unset($parts['port']);

      if(isset($parts['port']))
        $result .= ":" . $parts['port'];
    }

    if(isset($parts['path']))
    {
      if(isset($parts['host']) && $parts['path'][0] !== '/')
        throw new \UnexpectedValueException("Host is set but path is not absolute; unable to convert to string");

      $path = explode('%2F', $parts['path']);
      $result .= implode('%2F', array_map(function($part){
        /*
          BUG?: paths containing, f.e., "@" are encoded.
          For future reference:
          https://tools.ietf.org/html/rfc3986#section-2.2
        */
        return implode('/', array_map('rawurlencode', explode('/', $part)));
      }, $path));
    }

    if(isset($parts['query']))
    {
      if(is_array($parts['query']))
      {
        $query = $parts['query'];
      }
      else
      {
        parse_str($parts['query'], $query);
      }
      $result .= "?" . http_build_query($query);
    }

    if(isset($parts['fragment']))
      $result .= "#" . rawurlencode($parts['fragment']);

    return $this->uri = $result;
  }

// ArrayAccess

  /** @internal
  @see \ArrayAccess::offsetExists() */
  public function offsetExists($offset)
  {
    return isset($this->params['query'][$offset]);
  }

  /** @internal
  @see \ArrayAccess::offsetGet() */
  public function offsetGet($offset)
  {
    return $this->params['query'][$offset];
  }

  /** @internal
  @see \ArrayAccess::offsetSet() */
  public function offsetSet($offset, $value)
  {
    throw new \LogicException('Forbidden.');
  }

  /** @internal
  @see \ArrayAccess::offsetUnset() */
  public function offsetUnset($offset)
  {
    throw new \LogicException('Forbidden.');
  }

// Countable

  /** @internal
  @see \Countable::count() */
  public function count()
  {
    return empty($this->params['query']) ? 0 : count($this->params['query']);
  }

// IteratorAggregate

  /** @internal
  @see \IteratorAggregate::getIterator() */
  public function getIterator()
  {
    return new \ArrayIterator($this->params['query']);
  }
}


<?php
/**
 * This file is part of the EkiPayumNganluong package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Action;

use Eki\Payum\Nganluong\Api;
use Eki\Payum\Nganluong\Api\State\StateInterface;

use Payum\Core\Action\ActionInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Request\GetStatusInterface;
use Payum\Core\Exception\RequestNotSupportedException;

class StatusAction implements ActionInterface, StateInterface
{
    /**
     * {@inheritDoc}
     *
     * @param GetStatusInterface $request
     */

    /**
     * {@inheritDoc}
     *
     * @param GetStatusInterface $request
     */
    public function execute($request)
    {
        RequestNotSupportedException::assertSupports($this, $request);

        $model = new ArrayObject($request->getModel());

        $state = $model['state'];

        if (null === $state ||
            StateInterface::STATE_WAITING === $state
        ) {
            $request->markNew();

            return;
        }

        if (StateInterface::STATE_REPLIED === $state ||
            StateInterface::STATE_NOTIFIED === $state
        ) {
            $request->markPending();

            return;
        }

        if (StateInterface::STATE_CONFIRMED === $state) {
            $request->markCaptured();

            return;
        }

        $request->markFailed();
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof GetStatusInterface &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
/** Base GPS coordinates class
*
* @version SVN: $Id: Coordinate3D.php 738 2018-03-03 19:03:36Z anrdaemon $
*/

namespace AnrDaemon\Misc;

use
  ArrayAccess, Countable, Iterator,
  InvalidArgumentException, LogicException;

class Coordinate3D
  implements
    ArrayAccess,
    Countable,
    Iterator
{
  protected $gps = array(
    'x' => 0,
    'y' => 0,
    'z' => 0,
  );

  protected $precision = 2;

  public function __construct($x, $y, $z, $precision = 2)
  {
    if(!is_numeric($x) || !is_numeric($y) || !is_numeric($z) || !is_numeric($precision))
      throw new InvalidArgumentException('All arguments must be numeric.');

    $this->gps['x'] = (float)$x;
    $this->gps['y'] = (float)$y;
    $this->gps['z'] = (float)$z;
    $this->precision = (int)$precision;
  }

  /** Construct coordinate by the vector length and direction.
  *
  * @param $length the vector length
  * @param $ap angle in XY plane (in radians)
  * @param $av angle off XY plane (in radians)
  */
  public static function fromPolar($length, $ap, $av)
  {
    return new static($length * cos($ap) * cos($av), $length * sin($ap) * cos($av), $length * sin($av));
  }

  /** Distance between two coordinates.
  *
  * @param Coordinate3D|int $target|$x the point to calculate distance to
  * @param ?int $y the point to calculate distance to
  * @param ?int $z the point to calculate distance to
  * @return float distance
  */
  public function distance($target, $y = null, $z = null)
  {
    if($target instanceof self)
    {
      $_x = $this->gps['x'] - $target->gps['x'];
      $_y = $this->gps['y'] - $target->gps['y'];
      $_z = $this->gps['z'] - $target->gps['z'];
    }
    else
    {
      $_x = $this->gps['x'] - $target;
      $_y = $this->gps['y'] - $y;
      $_z = $this->gps['z'] - $z;
    }
    return sqrt($_x*$_x + $_y*$_y + $_z*$_z);
  }

  /** Translate coordinate in space
  *
  * @param Coordinate3D|int $shift|$x the distances by which a coordinate must be translated.
  * @param ?int $y the distances by which a coordinate must be translated.
  * @param ?int $z the distances by which a coordinate must be translated.
  * @return Coordinate3D the translated coordinate
  */
  public function translate($shift, $y = null, $z = null)
  {
    if($shift instanceof self)
      return new static($this->gps['x'] + $shift->gps['x'], $this->gps['y'] + $shift->gps['y'], $this->gps['z'] + $shift->gps['z']);
    else
      return new static($this->gps['x'] + $shift, $this->gps['y'] + $y, $this->gps['z'] + $z);
  }

  public function format($format = null, $decimals = null, $thousands = null)
  {
    if(isset($format))
    {
      if(isset($decimals) || isset($thousands))
      {
        if(isset($decimals) && isset($thousands))
          return sprintf($format,
            number_format($this->gps['x'], $this->precision, $decimals, $thousands),
            number_format($this->gps['y'], $this->precision, $decimals, $thousands),
            number_format($this->gps['z'], $this->precision, $decimals, $thousands)
            );
        else
          throw new InvalidArgumentException('Decimals and thousands separators must be both set or both unset.');
      }
      else
        return sprintf($format, $this->gps['x'], $this->gps['y'], $this->gps['z']);
    }
    else
      return sprintf('%s, %s, %s',
        number_format($this->gps['x'], $this->precision, '.', "'"),
        number_format($this->gps['y'], $this->precision, '.', "'"),
        number_format($this->gps['z'], $this->precision, '.', "'")
        );
  }

  final public function __get($name)
  {
    if(isset($this->gps[$name]))
      return $this->gps[$name];
    else if($name == "precision")
      return $this->precision;

    throw new LogicException("No such property \`{$name}\' or property is not readable.");
  }

  final public function __set($name, $value)
  {
    if($name == "precision")
    {
      $this->precision = (int)$value;
      return;
    }

    throw new LogicException("No such property \`{$name}\', invalid value for property or property is not writable.");
  }

  final public function __toString()
  {
    return $this->format();
  }

  final public function __debugInfo()
  {
    return array('gps' => $this->gps, 'precision' => $this->precision);
  }

// \ArrayAccess implementation for coordinates.

  public function offsetExists($offset)
  {
    return isset($this->gps[$offset]);
  }

  public function offsetGet($offset)
  {
    return $this->$offset;
  }

  public function offsetSet($offset, $value)
  {
    if(!isset($this->gps[$offset]))
      throw new LogicException('Forbidden.');

    $this->gps[$offset] = (float)$value;
  }

  public function offsetUnset($offset)
  {
    throw new LogicException('Forbidden.');
  }

// \Countable

  public function count()
  {
    return count($this->gps);
  }

// \Iterator

  protected $position = 0;

  public function current()
  {
    return $this->valid() ? current($this->gps) : null;
  }

  public function key()
  {
    return $this->valid() ? key($this->gps) : null;
  }

  public function next()
  {
    if($this->valid())
    {
      $this->position++;
      next($this->gps);
    }
    return;
  }

  public function rewind()
  {
    reset($this->gps);
    $this->position = 0;
    return;
  }

  public function valid()
  {
    return $this->position < count($this->gps);
  }
}


<?php
/**
 * This file is part of the EkiPayumBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Action;

use Eki\Payum\Nganluong\Api;
use Eki\Payum\Nganluong\Api\Errors;
use Eki\Payum\Nganluong\Api\TransactionStatus;
use Eki\Payum\Nganluong\Api\State\StateInterface;
use Eki\Payum\Nganluong\Request\Log;
use Eki\Payum\Nganluong\Request\Api\SetExpressCheckout;
use Eki\Payum\Nganluong\Request\Api\GetTransactionDetails;

use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\ApiAwareInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\Reply\HttpRedirect;
use Payum\Core\Request\Capture;
use Payum\Core\Request\Sync;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Request\ObtainCreditCard;
use Payum\Core\Exception\UnsupportedApiException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Security\SensitiveValue;
use Payum\Core\Security\GenericTokenFactoryInterface;

class CaptureAction extends PaymentAwareAction implements ApiAwareInterface
{
    /**
     * @var Api
     */
    protected $api;

	/**
	*
	* @var Payum\Core\Security\GenericTokenFactoryInterface
	*
	*/
	protected $tokenFactory;

    /**
     * {@inheritDoc}
     */
    public function setApi($api)
    {
        if (false == $api instanceof Api) {
            throw new UnsupportedApiException('Api not supported.');
        }

        $this->api = $api;
    }

	/**
	* Sets token factory
	*
	* @param GenericTokenFactoryInterface $tokenFactory
	*
	*/
	public function setTokenFactory(GenericTokenFactoryInterface $tokenFactory)
	{
		$this->tokenFactory = $tokenFactory;
	}

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Capture */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if ( !isset($model['token']) || false === $model['token'] )
		{
/*
            if (false == $model['return_url'] && $request->getToken()) {
                $model['return_url'] = $request->getToken()->getTargetUrl();
            }

            if (false == $model['cancel_url'] && $request->getToken()) {
                $model['cancel_url'] = $request->getToken()->getTargetUrl();
            }
*/
            if (false == $model['return_url'] || false == $model['cancel_url'])
			{
	            $notifyToken = $this->tokenFactory->createNotifyToken(
	                $request->getToken()->getPaymentName(),
	                $request->getToken()->getDetails()
	            );

                $model['return_url'] = false == $model['return_url'] ? $notifyToken->getTargetUrl() : $model['return_url'];
                $model['cancel_url'] = false == $model['cancel_url'] ? $notifyToken->getTargetUrl() : $model['cancel_url'];
            }

			$model['state'] = StateInterface::STATE_WAITING;
            $this->payment->execute(new SetExpressCheckout($model));

            if ( isset($model['error_code']) && $model['error_code'] === Errors::ERRCODE_NO_ERROR )
			{
		        if (isset($model['checkout_url']))
				{
					$model['state'] = StateInterface::STATE_REPLIED;
					$this->payment->execute(new Log('checkout_url='.$model['checkout_url']));
		            throw new HttpRedirect($model['checkout_url']);
		        }
				else
				{
					$model['state'] = StateInterface::STATE_ERROR;
					$this->execute(new Log('No checkout_url returned.'));
				}
            }
/*
			else
			{
				$model['state'] = StateInterface::STATE_ERROR;

				$errMsg = 'Error from SetExpressCheckout.';
				$errMsg .= '{error_code='.$model['error_code'].'}';
				$errMsg .= '{description='.$model['description'].'}';
				$this->payment->execute(new Log($errMsg));
			}
        }
		else
		{
	        $this->payment->execute(new GetTransactionDetails($model));
	        if ( isset($model['error_code']) && $model['error_code'] === Errors::ERRCODE_NO_ERROR )
			{
				if ( !isset($model['transaction_status']) )
				{
					$model['state'] = StateInterface::STATE_ERROR;
					$this->execute(new Log('GetTransactionDetails has no transaction status.'));
				}

				if ( $model['transaction_status'] === TransactionStatus::PAID)
				{
					$model['state'] = StateInterface::STATE_CONFIRMED;
					$this->execute(new Log('GetTransactionDetails -> Paid.'));

					return;
				}

				if ( $model['transaction_status'] === TransactionStatus::PAID_WAITING_FOR_PROCESS)
				{
					$model['state'] = StateInterface::STATE_NOTIFIED;
					$this->execute(new Log('GetTransactionDetails -> Waiting for paying.'));

					return;
				}

				if ( $model['transaction_status'] === TransactionStatus::NOT_PAID)
				{
					$model['state'] = StateInterface::STATE_ERROR;
					$this->execute(new Log('GetTransactionDetails-> Not paid'));

					return;
				}
			}
			else
			{
				$model['state'] = StateInterface::STATE_ERROR;
				$this->execute(new Log('Unknown error when checking payment.'));

				return;
			}
		}
*/
    }

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Capture &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php
/**
 * This file is part of the EkiSyliusPayumBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Bridge\Sylius;

use Payum\Core\Security\GenericTokenFactoryInterface;
use Payum\Core\Security\TokenInterface;
use Sylius\Bundle\PayumBundle\Payum\Action\AbstractCapturePaymentAction;
use Sylius\Component\Core\Model\AdjustmentInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Payment\Model\PaymentInterface;

class CapturePaymentUsingNganluongAction extends AbstractCapturePaymentAction
{
	const DEFAULT_PAYMENT_TYPE = 1;

    /**
     * @var GenericTokenFactoryInterface
     */
    protected $tokenFactory;

    /**
     * @param GenericTokenFactoryInterface $tokenFactory
     */
    public function __construct(GenericTokenFactoryInterface $tokenFactory)
    {
        $this->tokenFactory = $tokenFactory;
    }

    /**
     * {@inheritdoc}
     */
    protected function composeDetails(PaymentInterface $payment, TokenInterface $token)
    {
        if ($payment->getDetails()) {
            return;
        }

        $order = $payment->getOrder();

        $details = array();

		$details['payment_method'] = $this->apiMethod(strtolower($payment->getMethod()->getName()));
		$details['payment_type'] = self::DEFAULT_PAYMENT_TYPE;

        $details['order_code'] = $order->getNumber().'-'.$payment->getId();
        $details['cur_code'] = $order->getCurrency();
        $details['total_amount'] = round($order->getTotal() / 100, 2);
		$details['total_item'] = count($order->getItems());

        $m = 0;
        foreach ($order->getItems() as $item)
		{
            $details['item_name'.$m] = $item->getId();
            $details['item_amount'.$m] = round($item->getTotal()/$item->getQuantity()/100, 2);
            $details['item_quantity'.$m] = $item->getQuantity();

            $m++;
        }

        if (0 !== $taxTotal = $this->calculateNonNeutralTaxTotal($order)) {
            $details['tax_amount']  = $taxTotal;
        }

        if (0 !== $promotionTotal = $order->getAdjustmentsTotal(AdjustmentInterface::PROMOTION_ADJUSTMENT)) {
            $details['discount_amount']  = $promotionTotal;
        }

        if (0 !== $shippingTotal = $order->getAdjustmentsTotal(AdjustmentInterface::SHIPPING_ADJUSTMENT)) {
            $details['fee_shipping']  = $shippingTotal;
        }

        $payment->setDetails($details);
    }

	private function apiMethod($methodName)
	{
		$mappings = array(
			'nganluong_visa' => 'VISA',
			'nganluong_atm' => 'ATM_ONLINE',
			'van phong ngan luong' => 'TTVP',
			'vi ngan luong' => 'NL',
		);

		if ( in_array( $methodName, array_keys($mappings) ) )
		{
			return $mappings[$methodName];
		}
		else
		{
			return $methodName;
		}
	}

    private function calculateNonNeutralTaxTotal(OrderInterface $order)
    {
        $nonNeutralTaxTotal = 0;
        foreach ($order->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT) as $taxAdjustment) {
            if (!$taxAdjustment->isNeutral()) {
                $nonNeutralTaxTotal = $taxAdjustment->getAmount();
            }
        }

        return $nonNeutralTaxTotal;
    }
}


<?php
/**
 * This file is part of the EkiPayumNganluongBundle package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong\Action;

use Eki\Payum\Nganluong\Api;
use Eki\Payum\Nganluong\Api\Errors;
use Eki\Payum\Nganluong\Api\TransactionStatus;
use Eki\Payum\Nganluong\Api\State\StateInterface;
use Eki\Payum\Nganluong\Request\Log;
use Eki\Payum\Nganluong\Request\Api\SetExpressCheckout;
use Eki\Payum\Nganluong\Request\Api\GetTransactionDetails;

use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\ApiAwareInterface;
use Payum\Core\Bridge\Spl\ArrayObject;
use Payum\Core\Exception\LogicException;
use Payum\Core\Reply\HttpRedirect;
use Payum\Core\Request\Capture;
use Payum\Core\Request\GetHttpRequest;
use Payum\Core\Request\ObtainCreditCard;
use Payum\Core\Exception\UnsupportedApiException;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Security\SensitiveValue;
use Payum\Core\Security\GenericTokenFactoryInterface;

class CaptureAction extends PaymentAwareAction implements ApiAwareInterface
{
    /**
     * @var Api
     */
    protected $api;

    /**
     * {@inheritDoc}
     */
    public function setApi($api)
    {
        if (false == $api instanceof Api) {
            throw new UnsupportedApiException('Api not supported.');
        }

        $this->api = $api;
    }

	/**
	* Sets token factory
	*
	* @param GenericTokenFactoryInterface $tokenFactory
	*
	*/
	public function setTokenFactory(GenericTokenFactoryInterface $tokenFactory)
	{
		$this->tokenFactory = $tokenFactory;
	}

    /**
     * {@inheritDoc}
     */
    public function execute($request)
    {
        /** @var $request Capture */
        RequestNotSupportedException::assertSupports($this, $request);

        $model = ArrayObject::ensureArrayObject($request->getModel());

        if ( false == $model['token'] )
		{
			$this->payment->execute(new Log('No token. First....', $this));

            if (false == $model['return_url'] && $request->getToken()) {
                $model['return_url'] = $request->getToken()->getTargetUrl();
            }

            if (false == $model['cancel_url'] && $request->getToken()) {
                $model['cancel_url'] = $request->getToken()->getTargetUrl();
            }

			$model['state'] = StateInterface::STATE_WAITING;
			$this->payment->execute(new Log('Waiting for reply when calling SetExpressCheckout', $this));
            $this->payment->execute(new SetExpressCheckout($model));

            if ( isset($model['error_code']) && $model['error_code'] === Errors::ERRCODE_NO_ERROR )
			{
		        if (isset($model['checkout_url']))
				{
					$model['state'] = StateInterface::STATE_REPLIED;
					$this->payment->execute(new Log('checkout_url='.$model['checkout_url'], $this));
		            throw new HttpRedirect($model['checkout_url']);
		        }
				else
				{
					$model['state'] = StateInterface::STATE_ERROR;
					$this->payment->execute(new Log('No checkout_url returned.', $this));
				}
            }
		}

		else
		{
			$this->payment->execute(new Log('Before calling GetTransactionDetails', $this));
			$this->logAllModel($model);

	        $copiedModel = new ArrayObject(array(
	            'token' => $model['token'],
	        ));

            $this->payment->execute(new GetTransactionDetails($copiedModel));

			$this->payment->execute(new Log('After calling GetTransactionDetails', $this));
			$this->logAllModel($copiedModel);

			if ( $copiedModel['error_code'] === Errors::ERRCODE_NO_ERROR )
			{
				$model['bank_code'] = $copiedModel['bank_code'];
				$model['transaction_id'] = $copiedModel['transaction_id'];
				$model['transaction_status'] = $copiedModel['transaction_status'];

				if ( $copiedModel['transaction_status'] == TransactionStatus::PAID )
				{
					$model['state'] = StateInterface::STATE_CONFIRMED;
					$this->payment->execute(new Log('Order paid. OK. OK. OK.', $this));
				}
				else if ( $copiedModel['transaction_status'] == TransactionStatus::NOT_PAID )
				{
					$model['state'] = StateInterface::STATE_ERROR;
					$this->payment->execute(new Log('Payer decided to avoid payment', $this));
				}
				else if ( $copiedModel['transaction_status'] == TransactionStatus::PAID_WAITING_FOR_PROCESS )
				{
					$model['state'] = StateInterface::STATE_NOTIFIED;
					$this->payment->execute(new Log('Payment process notified but not captured.', $this));
				}
				else
				{
					$model['state'] = StateInterface::STATE_ERROR;
					$this->payment->execute(new Log('Payment process return OK but transaction status is not invalid. Unknown error !!!', $this));
				}
			}
			else
			{
				$model['state'] = StateInterface::STATE_ERROR;
				$this->payment->execute(new Log('Error after calling GetTransactionDetails', $this));
			}
		}
    }

	private function logAllModel($model)
	{
		$msg = '';
		foreach($model as $key => $value)
		{
			$msg .= '  '.$key.'='.$value;
		}
		$this->payment->execute(new Log($msg, $this));
	}

    /**
     * {@inheritDoc}
     */
    public function supports($request)
    {
        return
            $request instanceof Capture &&
            $request->getModel() instanceof \ArrayAccess
        ;
    }
}


<?php

namespace FondOfSpryker\Client\AvailabilityAlert;

use FondOfSpryker\Client\AvailabilityAlert\Dependency\Client\AvailabilityAlertToZedRequestBridge;
use Spryker\Client\Kernel\AbstractDependencyProvider;
use Spryker\Client\Kernel\Container;

class AvailabilityAlertDependencyProvider extends AbstractDependencyProvider
{
    const CLIENT_ZED_REQUEST = 'CLIENT_ZED_REQUEST';

    /**
     * @param \Spryker\Client\Kernel\Container $container
     *
     * @return \Spryker\Client\Kernel\Container
     */
    public function provideServiceLayerDependencies(Container $container)
    {
        $container = $this->addZedRequestClient($container);

        return $container;
    }

    /**
     * @param \Spryker\Client\Kernel\Container $container
     *
     * @return \Spryker\Client\Kernel\Container
     */
    protected function addZedRequestClient(Container $container)
    {
        $container[static::CLIENT_ZED_REQUEST] = function (Container $container) {
            return new AvailabilityAlertToZedRequestBridge($container->getLocator()->zedRequest()->client());
        };

        return $container;
    }
}


<?php
/**
 * This file is part of the EkiPayum package.
 *
 * (c) EkiPower <http://ekipower.github.com/>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace Eki\Payum\Nganluong;

use Eki\Payum\Nganluong\Api\ApiInterface;
use Eki\Payum\Nganluong\Api\AbstractApi;
use Eki\Payum\Nganluong\Api\Errors;
use Eki\Payum\Nganluong\Api\ApiException;

use Buzz\Client\ClientInterface;
use Buzz\Message\Form\FormRequest;
use Eki\Payum\Nganluong\Bridge\Buzz\Response;
use Payum\Core\Bridge\Buzz\ClientFactory;
use Payum\Core\Exception\Http\HttpException;
use Payum\Core\Exception\InvalidArgumentException;
use Payum\Core\Exception\RuntimeException;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;

class Api extends AbstractApi implements LoggerAwareInterface
{
    const VERSION = '3.1';

	/**
	*
	* @var Buzz\Client\ClientInterface
	*
	*/
    protected $client;

	/**
	*
	* @var Psr\Log\LoggerInterface
	*
	*/
	private $logger;

	/**
	*
	* @var array
	*
	*/
    protected $options = array(
        'merchant_id' => null,
        'merchant_password' => null,
        'receiver_email' => null,
        'sandbox' => null,
        'sandbox_url' => null,
        'return_url' => null,
        'cancel_url' => null,
    );

	public function setLogger(LoggerInterface $logger)
	{
		$this->logger = $logger;
	}

    /**
     * @param array $options
     * @param ClientInterface|null $client
     */
    public function __construct(array $options, ClientInterface $client = null)
    {
        $this->options = array_replace($this->options, $options);

        if (true == empty($this->options['merchant_id'])) {
            throw new \InvalidArgumentException('The merchant id option must be set.');
        }
        if (true == empty($this->options['merchant_password'])) {
            throw new \InvalidArgumentException('The merchant password option must be set.');
        }
        if (true == empty($this->options['receiver_email'])) {
            throw new \InvalidArgumentException('The receiver email as NL account option must be set.');
        }
        if (false == is_bool($this->options['sandbox'])) {
            throw new \InvalidArgumentException('The boolean sandbox option must be set.');
        }

        $this->client = $client ?: ClientFactory::createCurl();
    }

	/**
	* @inheritdoc
	*/
	public function getVersion()
	{
		return self::VERSION;
	}

	/**
	* @inheritdoc
	*/
	public function checkFields(array $fields)
	{
		$this->checkVersion($fields);
		$this->checkAuthorize($fields);
	}

	/**
	* Check version
	* @internal: called by checkFields function
	*
	* @param array $fields
	* @throw ApiException
	*/
	private function checkVersion(array $fields)
	{
		if ( false === $fields['version'] || $fields['version'] !== $this->getVersion() )
		{
			throw new ApiException(Errors::ERRCODE_VERSION_WRONG);
		}
	}

	/**
	* Check ahthorize
	* @internal: called by checkFields function
	*
	* @param array $fields
	* @throw ApiException
	*/
	private function checkAuthorize(array $fields)
	{
		if ( false === $fields['merchant_id'] )
		{
			throw new ApiException(Errors::ERRCODE_MERCHANT_ID_INVALID);
		}
		if ( false === $fields['merchant_password'] )
		{
			throw new ApiException(Errors::ERRCODE_MERCHANT_PASSWORD_INVALID);
		}
		if ( false === $fields['receiver_email'] )
		{
			throw new ApiException(Errors::ERRCODE_MERCHANT_EMAIL_INVALID);
		}
	}

	/**
	* @inheritdoc
	*/
	protected function getSupportedFunctions()
	{
		return array(
			'SetExpressCheckout' => 'setExpressCheckout',
			'GetTransactionDetail' => 'getTransactionDetails'
		);
	}

	/**
	* Wrapper of setExpressCheckout function
	*
	* @param array $fields
	*
	*/
    public function setExpressCheckout(array $fields)
	{
		return $this->doFunction($fields + array('function'=>'SetExpressCheckout'));
	}

    /**
     * Require:
     *
     * @param array $fields
     *
     * @return array
     */
    protected function doFunction_setExpressCheckout(array $fields)
    {
        $request = new FormRequest;
        $request->setFields($fields);

        if (!isset($fields['return_url'])) {
            if (false == $this->options['return_url']) {
                throw new RuntimeException('The return_url must be set either to FormRequest or to options.');
            }

            $request->setField('return_url', $this->options['return_url']);
        }

        if (!isset($fields['cancel_url'])) {
            if (false == $this->options['cancel_url']) {
                throw new RuntimeException('The cancel_url must be set either to FormRequest or to options.');
            }

            $request->setField('cancel_url', $this->options['cancel_url']);
        }

        $request->setField('function', 'SetExpressCheckout');

        $this->addVersionField($request);
        $this->addAuthorizeFields($request);

        return $this->doRequest($request);
    }

	/**
	* Wrapper of getTransactionDetails function
	*
	* @param array $fields
	*
	*/
    public function getTransactionDetails(array $fields)
	{
		return $this->doFunction($fields + array('function'=>'GetTransactionDetail'));
	}

    /**
     * Require: token
     *
     * @param array $fields
     *
     * @return array
     */
    protected function doFunction_getTransactionDetails(array $fields)
    {
        if (!isset($fields['token'])) {
            throw new RuntimeException('The token must be set.');
        }

        $request = new FormRequest;
        $request->setFields($fields);

        $request->setField('function', 'GetTransactionDetail');

        $this->addVersionField($request);
        $this->addAuthorizeFields($request);

        return $this->doRequest($request);
    }

    /**
     * @param FormRequest $request
     *
     * @throws HttpException
     *
     * @return array
     */
    protected function doRequest(FormRequest $request)
    {
        $request->setMethod('POST');
        $request->fromUrl($this->getApiEndpoint());

        $this->client->send($request, $response = new Response);

        if (false == $response->isSuccessful())
		{
            throw HttpException::factory($request, $response);
        }
		else
		{
			return $response->toArray();
		}
    }

    /**
     * @return string
     */
    protected function getApiEndpoint()
    {
        return
			$this->options['sandbox'] === true						          ?
            (
				!isset($this->options['sandbox_url'])                      ?
				'https://www.nganluong.vn/checkout.api.nganluong.post.php' :
				$this->options['sandbox_url']
			)                                                                 :
            'https://www.nganluong.vn/checkout.api.nganluong.post.php' 		  ;
    }

    /**
     * @param FormRequest $request
     */
    protected function addAuthorizeFields(FormRequest $request)
    {
        $request->setField('merchant_id', $this->options['merchant_id']);
        $request->setField('merchant_password', md5($this->options['merchant_password']));
        $request->setField('receiver_email', $this->options['receiver_email']);
    }

    /**
     * @param FormRequest $request
     */
    protected function addVersionField(FormRequest $request)
    {
        $request->setField('version', self::VERSION);
    }

	public function getErrorMessages()
	{
		return Errors::ErrorMessages();
	}

	public function getErrorMessage($code)
	{
		$messages = Errors::ErrorMessages();
		return $messages[$code];
	}
}


<?php
//
// +---------------------------------------------------------------------+
// | CODE INC. SOURCE CODE                                               |
// +---------------------------------------------------------------------+
// | Copyright (c) 2017 - Code Inc. SAS - All Rights Reserved.           |
// | Visit https://www.codeinc.fr for more information about licensing.  |
// +---------------------------------------------------------------------+
// | NOTICE:  All information contained herein is, and remains the       |
// | property of Code Inc. SAS. The intellectual and technical concepts  |
// | contained herein are proprietary to Code Inc. SAS are protected by  |
// | trade secret or copyright law. Dissemination of this information or |
// | reproduction of this material  is strictly forbidden unless prior   |
// | written permission is obtained from Code Inc. SAS.                  |
// +---------------------------------------------------------------------+
//
// Author:   Joan Fabrégat <joan@codeinc.fr>
// Date:     08/03/2018
// Time:     17:07
// Project:  SessionManager
//
declare(strict_types = 1);
namespace CodeInc\SessionManager;
use CodeInc\SessionManager\Exceptions\SessionMiddlewareException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * Class SessionMiddleware
 *
 * @package CodeInc\Session\Middleware
 * @author Joan Fabrégat <joan@codeinc.fr>
 */
class SessionMiddleware implements MiddlewareInterface
{
    public const REQ_ATTR = '__sessionManager';

    /**
     * @var SessionManager
     */
    private $sessionManager;

    /**
     * SessionMiddleware constructor.
     *
     * @param SessionManager $sessionManager
     * @param null|MiddlewareInterface $nextMiddleware
     */
    public function __construct(SessionManager $sessionManager)
    {
        $this->sessionManager = $sessionManager;
    }

    /**
     * @return SessionManager
     */
    public function getSessionManager():SessionManager
    {
        return $this->sessionManager;
    }

    /**
     * @inheritdoc
     * @throws \CodeInc\SessionManager\Exceptions\SessionManagerException
     */
    public function process(ServerRequestInterface $request,
        RequestHandlerInterface $handler):ResponseInterface
    {
        // get the session manager and starts the session if not started
        $session = $this->sessionManager->start($request);

        // processes the response
        $response = $handler->handle(
            $request->withAttribute(static::REQ_ATTR, $session)
        );

        // if the response is a HTML page, attaches the cookie
        if (preg_match("#^text/html#ui", $response->getHeaderLine("Content-Type"))) {
            $response = $this->sessionManager->getSessionCookie()->addToResponse($response);
        }

        return $response;
    }

    /**
     * Returns the session object attached to a request.
     *
     * @param ServerRequestInterface $request
     * @return SessionDataHolder
     * @throws SessionMiddlewareException
     */
    public static function getSession(ServerRequestInterface $request):SessionDataHolder
    {
        $session = $request->getAttribute(static::REQ_ATTR);
        if (!$session instanceof SessionDataHolder) {
            throw new SessionMiddlewareException(
                "No session object is available in the request attributes"
            );
        }
        return $session;
    }
}