<file_sep><?php

namespace Pythagus\Lydia\Contracts;

/**
 * Interface LydiaState
 * @package Pythagus\Lydia\Contracts
 * @see https://lydia-app.com/doc/api/#api-Payment-State
 *
 * @author: <NAME>
 */
interface LydiaState {

    /**
     * Unknown transaction state.
     *
     * @const int
     */
    public const UNKNOWN = -1 ;

    /**
     * State of a waiting payment. A transaction
     * request was addressed to Lydia.
     *
     * @const int
     */
    public const WAITING_PAYMENT = 0 ;

    /**
     * The payment was confirmed by Lydia.
     *
     * @const int
     */
    public const PAYMENT_CONFIRMED = 1 ;

    /**
     * The payment was refused by the bank.
     *
     * @const int
     */
    public const REFUSED_BY_PAYER = 5 ;

    /**
     * The payment was cancelled by the client
     * before the end.
     *
     * @const int
     */
    public const CANCELLED_BY_OWNER = 6 ;

}<file_sep><?php

namespace Pythagus\Lydia\Traits;

use Pythagus\Lydia\Lydia;

/**
 * Trait HasLydiaProperties
 * @package Pythagus\Lydia\Traits
 *
 * @author: <NAME>
 */
trait HasLydiaProperties {

    /**
     * Determine whether the website is in a
     * lydia debugging mode.
     *
     * @return bool
     */
    protected function isTestingMode() {
        return boolval($this->getConfig('debug', false)) ;
    }

    /**
     * Get the PaymentLydia server's URL
     *
     * @return string
     */
    protected function getLydiaURL() {
        return $this->getLydiaCredential('url_server') ;
    }

    /**
     * Get the PaymentLydia vendor token.
     *
     * @return string
     */
    protected function getLydiaVendorToken() {
        return $this->getLydiaCredential('vendor_token') ;
    }

    /**
     * Get the PaymentLydia private token.
     *
     * @return string
     */
    protected function getLydiaPrivateToken() {
        return $this->getLydiaCredential('private_token') ;
    }

    /**
     * Get the property in the lydia.php file
     * using the debug value.
     *
     * @param string $property
     * @return string
     */
    protected function getLydiaCredential(string $property) {
        $mode = $this->isTestingMode() ? 'debug' : 'prod' ;

        return $this->getConfig('credentials.'.$mode.'.'.$property) ;
    }

    /**
     * Get the config value.
     *
     * @param string $key
     * @param null $default
     * @return mixed|null
     */
    protected function getConfig(string $key, $default = null) {
        return Lydia::getInstance()->config($key, $default) ;
    }
}<file_sep><?php

namespace Pythagus\Lydia\Http;

use Pythagus\Lydia\Contracts\LydiaException;

/**
 * Class RefundRequest
 * @package Pythagus\Lydia\Http
 *
 * @property string identifier
 *
 * @author: <NAME>
 */
class RefundRequest extends LydiaRequest {

    /**
     * Payment identifier given in the
     * Lydia return after a payment.
     *
     * @var string
     */
    private $identifier ;

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

    /**
     * Execute the request.
     *
     * @return mixed
     * @throws LydiaException
     */
    protected function run() {
        $this->setRequestParameters() ;

        $result = $this->requestServer('refund') ;

        /**
         * This method prevents to the Lydia problems that
         * can occurred. The incoming exception should not
         * be caught here to be printed to the client.
         *
         * @throws LydiaException
         */
        $this->lydiaResponseContains($result, 'error', true) ;

        /*
         * Here, the response should be a Std object
         * with keys:
         * - error: Set to 0 if there is no error.
         */
        return $result['error'] ;
    }

    /**
     * Get the list of required parameters for
     * the request.
     *
     * @return array
     */
    protected function shouldHaveParameters() {
        return ['amount'] ;
    }

    /**
     * Set the default parameters.
     *
     * @return void
     */
    protected function setRequestParameters() {
        $amount = $this->parameters['amount'] ;

        $this->clearParameters() ;
        $this->setParameter('transaction_identifier', $this->identifier) ;
        $this->setParameter('amount', $amount) ;
        $this->setParameter('signature', $this->generateSignature($this->parameters)) ;
        $this->setParameter('vendor_token', $this->getLydiaVendorToken()) ;
    }
}<file_sep><?php

namespace Pythagus\Lydia\Traits;

/**
 * Trait HasParameters
 * @package Pythagus\Lydia\Helpers
 *
 * @property array parameters
 *
 * @author: <NAME>
 */
trait HasParameters {

    /**
     * Request parameters.
     *
     * @var array
     */
    protected $parameters = [] ;

    /**
     * Set the parameter to the given value.
     *
     * @param string $field
     * @param $value
     */
    public function setParameter(string $field, $value) {
        $this->parameters[$field] = $value ;
    }

    /**
     * Reset all the parameters.
     *
     * @return void
     */
    public function clearParameters() {
        $this->parameters = [] ;
    }

    /**
     * Get the list of required parameters for
     * the request.
     *
     * @return array
     */
    protected function shouldHaveParameters() {
        return [] ;
    }

    /**
     * Set the default parameters.
     *
     * @return void
     */
    protected function setDefaultParameters() {
        //
    }
}<file_sep><?php

namespace Pythagus\Lydia\Http;

use Pythagus\Lydia\Contracts\LydiaException;

/**
 * Class PaymentStateRequest
 * @package Pythagus\Lydia\Http
 *
 * @property string requestUUID
 *
 * @author: <NAME>
 */
class PaymentStateRequest extends LydiaRequest {

    /**
     * Request UUID to check.
     * This attribute was given in the PaymentRequest response.
     *
     * @var string
     */
    private $requestUUID ;

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

    /**
     * Execute the request.
     *
     * @return mixed
     * @throws LydiaException
     */
    protected function run() {
        $result = $this->requestServer('state') ;

        /**
         * This method prevents to the Lydia problems that
         * can occurred. The incoming exception should not
         * be caught here to be printed to the client.
         *
         * @throws LydiaException
         */
        $this->lydiaResponseContains($result, 'error', false) ;
        $this->lydiaResponseContains($result, 'state', true) ;

        /*
         * Here, the response should be a Std object
         * with keys:
         * - state: Status of the remote request. See LydiaState contract interface.
         * - used_ease_of_payment: Specify if the user used ease of payment or not.
         */
        return intval($result['state']) ;
    }

    /**
     * Set the default parameters.
     *
     * @return void
     */
    protected function setDefaultParameters() {
        // Vendor token of the business that done the request.
        $this->setParameter('vendor_token', $this->getLydiaVendorToken()) ;

        // UUID of the remote payment request.
        $this->setParameter('request_uuid', $this->requestUUID) ;
    }
}<file_sep><?php

namespace Pythagus\Lydia\Contracts;

use Exception;
use Throwable;

/**
 * Class LydiaException
 * @package Pythagus\Lydia\Contracts
 *
 * @author: <NAME>
 */
class LydiaException extends Exception {

    /**
     * @param string $message
     * @param int $code
     * @param Throwable|null $previous
     */
    public function __construct($message = "", $code = 0, Throwable $previous = null) {
        parent::__construct(
            "Lydia : " . $message, $code, $previous
        ) ;
    }
}<file_sep># Lydia payment
[Lydia](https://lydia-app.com/fr) is an online-payment solution. This package presents an implementation of this tool in 
an Object-Oriented view. This is a stand-alone package.

## Version
This package works since PHP 7.3. Please refer to the next table to check whether your PHP version is compatible with this package.

|Package version|PHP version|
|---------------|-----------|
| 1.x           | 7.x, 8.x  |


## Installation

### With composer
Use the package manager [composer](https://getcomposer.org/) to install this package.

```bash
composer require pythagus/lydia
```

### Without package manager
You can clone the current repository and completely use this package. You need to make (or use) an autoload package 
(like [composer](https://getcomposer.org/)) to correctly discover the files.

## Usage
This section describes how to correctly and fully use this package.

### The Lydia facade
The ```Pythagus\Lydia\Lydia``` class allows you to custom the Lydia main interactions with your application. 
**You need to extend this class**. The package won't work otherwise. You can refer to the [example/MyLydiaFacade](example/MyLydiaFacade) 
class to have an example how to override this class.

When you override the ```Lydia``` class, you need to àdd the next line to be taking into account:
```php 
Lydia::setInstance(new MyLydiaFacade()) ;
```
If you are using a framework, you can add this line when your application is starting. If you are not, you need to add this 
line before every request you make.

**Note :** if you are using a framework, you will probably have a redirect response manager. So you can override the ```Lydia.redirect()``` 
method to use your framework instead.

### Configuration
You have an example of a configuration file in the [example folder](example). The ```MyLydiaFacade``` class show you what you should 
override to adapt this package to your application. I suggest you copying the ```lydia.php``` config file and only add your personal keys.

#### Properties
The ```properties``` key in the ```example/lydia.php``` config file allows you to declare some properties that won't change from a 
request to another (like the currency).

### Lydia requests
For now, the package implements 3 Lydia's requests:

#### PaymentRequest
Make a payment request to the Lydia's server. You need to use the ```setFinishCallback()``` method to define the return route using by 
Lydia to redirect the user. You also need to define **amount** and **recipient** parameters like:
```php
$request = new PaymentRequest() ;
$request->setFinishCallback('my/route') ;
$data = $request->execute([
	'amount'    => 5,
	'recipient' => '<EMAIL>'
]) ;

// Save your data.

return $request->redirect() ;
```

The ```execute()``` method will redirect the user to the Lydia's page. After payment, the user will be redirected to ```my/route```.

#### PaymentStateRequest
Check the state of a payment. You need to set the ```request_uuid``` that is given in the ```Lydia.savePaymentData()``` array when the payment is requested.
You can execute the request like:
```php
$request = new PaymentStateRequest("payment_request_uuid") ;
$state   = $request->execute() ;
```

#### RefundRequest
Refund partially or globally a transaction. You need to set the ```transaction_identifier``` that is given in the ```PaymentRequest``` finish route.
You need to add the **amount** parameter.
You can execute the request like:
```php
$request = new RefundRequest("payment_transaction_identifier") ;
$status  = $request->execute([
	'amount' => 10
]) ;
```

## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

## License
[MIT](LICENSE)<file_sep><?php

namespace Pythagus\Lydia\Http;

use anlutro\cURL\cURL;
use Pythagus\Lydia\Lydia;
use Pythagus\Lydia\Traits\HasParameters;
use Pythagus\Lydia\Contracts\LydiaException;
use Pythagus\Lydia\Traits\HasLydiaProperties;
use Pythagus\Lydia\Exceptions\InvalidLydiaResponseException;

/**
 * Class LydiaRequest
 * @package Pythagus\Lydia\Http
 *
 * @author: <NAME>
 */
abstract class LydiaRequest {

    use HasParameters, HasLydiaProperties ;

    /**
     * Execute the request.
     *
     * @return mixed
     */
    abstract protected function run() ;

    /**
     * Get a Lydia instance.
     *
     * @return Lydia
     */
    protected function lydia() {
        return Lydia::getInstance() ;
    }

    /**
     * Execute the request adding some parameters.
     *
     * @param array $parameters
     * @return mixed
     * @throws LydiaException
     */
    public function execute(array $parameters = []) {
        $this->setDefaultParameters();
        $this->addPropertiesOnArray($this->getConfig('properties', [])) ;
        $this->addPropertiesOnArray($parameters) ;

        foreach($this->shouldHaveParameters() as $parameter) {
            if(! array_key_exists($parameter, $this->parameters)) {
                throw new LydiaException(class_basename($this) . " should have a parameter : $parameter") ;
            }
        }

        return $this->run() ;
    }

    /**
     * Set the properties listed in the given array.
     *
     * @param array $properties
     */
    protected function addPropertiesOnArray(array $properties) {
        foreach($properties as $key => $value) {
            $this->setParameter($key, $value) ;
        }
    }

    /**
     * Check whether the Lydia response has the
     * expected format.
     *
     * @param array $response
     * @param $keys
     * @param bool $shouldHave
     * @throws LydiaException
     */
    protected function lydiaResponseContains(array $response, $keys, bool $shouldHave) {
        if(! is_array($keys)) {
            $keys = [$keys] ;
        }

        /*
         * We test every keys contained in
         * the $keys variable.
         */
        foreach($keys as $key) {
            $has = isset($response[$key]) ;

            /*
             * There is an error if:
             * -> The response should have the $key field and has not one.
             * -> The response should not have the $key field and has one.
             */
            if($shouldHave xor $has) {
                throw new InvalidLydiaResponseException(
                    "Lydia's response " . ($shouldHave ? "should" : "shouldn't") . " have $key attribute", $response
                ) ;
            }
        }
    }

    /**
     * Generate the request signature.
     *
     * @param array $param
     * @return string
     * @see: https://lydia-app.com/doc/api/#signature
     */
    protected function generateSignature(array $param) {
        /*
         * We are making a copy of the
         * given param to leave the given
         * value intact.
         */
        $data = $param ;

        // Alphabetical ordering
        ksort($data) ;

        return md5(
            http_build_query($data) . '&' . $this->getLydiaPrivateToken()
        ) ;
    }

    /**
     * Make a request server call.
     *
     * @param string $route : config key (lydia.url.$key) in lydia.php config file.
     * @return array
     */
    protected function requestServer(string $route) {
        $response = (new cURL())->post(
            $this->getLydiaURL() . $this->getConfig('url.' . $route), $this->parameters
        ) ;

        return json_decode($response->getBody(), true) ;
    }
}<file_sep><?php

use Pythagus\Lydia\Lydia;

/**
 * Class MyLydiaFacade
 *
 * @author: <NAME>
 */
class MyLydiaFacade extends Lydia {

	/**
	 * Get the Lydia's configuration.
	 *
	 * @return array
	 */
	protected function setConfigArray() {
		return require __DIR__ . '/lydia.php' ;
	}

	/**
	 * Format the callback URL to be valid
	 * regarding the Lydia server.
	 *
	 * @param string $url
	 * @return string
	 */
	public function formatCallbackUrl(string $url) {
		return 'https://www.google.com/' . $url ;
	}

}<file_sep><?php

namespace Pythagus\Lydia\Exceptions;

use Pythagus\Lydia\Contracts\LydiaException;

/**
 * Class InvalidLydiaResponseException
 * @package Pythagus\Lydia\Exceptions
 *
 * @property array response
 *
 * @author: <NAME>
 */
class InvalidLydiaResponseException extends LydiaException {

    /**
     * Make a new InvalidLydiaResponse exception.
     *
     * @param string $message : original exception message.
     * @param array $response
     */
    public function __construct(string $message, array $response) {
        parent::__construct(
            $message . '(response : ' . json_encode($response) . ')'
        ) ;
    }
}<file_sep><?php

namespace Pythagus\Lydia\Contracts;

/**
 * These error codes were generated from logs after
 * Lydia usages. This is not an exhaustive list.
 * 
 * Class PaymentErrorCode
 * @package Pythagus\Lydia\Contracts
 *
 * @author: <NAME>
 */
interface PaymentErrorCode {

    /**
     * Invalid email address given (recipient).
     * 
     * @var integer
     */
    public const INVALID_RECIPIENT = 3 ;

    /**
     * The recipient cannot receive more payment requests.
     * 
     * @var integer
     */
    public const FLOODED_RECIPIENT = 4 ;

    /**
     * The recipient was blocked.
     * 
     * @var integer
     */
    public const BLOCKED_RECIPIENT = 6 ;

}<file_sep><?php

namespace Pythagus\Lydia\Traits;

use Throwable;

/**
 * Trait LydiaTools
 * @package Pythagus\Lydia\Traits
 *
 * @author: <NAME>
 */
trait LydiaTools {

    /**
     * We are trying to take the transaction_identifier
     * token in the GET Lydia's response.
     *
     * @return string|null
     */
    public static function getTransactionIdentifier() {
        try {
            return $_GET['transaction'] ?? null ;
        } catch(Throwable $ignored) {
            return null ;
        }
    }
}<file_sep><?php

namespace Pythagus\Lydia\Traits;

use Pythagus\Lydia\Contracts\LydiaException;

/**
 * Trait HasConfig
 * @package Pythagus\Lydia\Traits
 *
 * @property array configs
 *
 * @author: <NAME>
 */
trait HasConfig {

    /**
     * Lydia's configurations
     *
     * @var array
     */
    private $configs = [] ;

    /**
     * Get the config value identified by
     * the given key.
     *
     * @param string $key
     * @param null $default
     * @return mixed|null
     */
    public function config(string $key, $default = null) {
        $array = $this->configs ;

        if(count($array) <= 0) {
            throw new LydiaException("No configs are loaded") ;
        }

        if(array_key_exists($key, $array)) {
            return $array[$key] ;
        }

        if(strpos($key, '.') === false) {
            return $array[$key] ?? $default ;
        }

        foreach(explode('.', $key) as $segment) {
            if(array_key_exists($segment, $array)) {
                $array = $array[$segment] ;
            } else {
                return $default ;
            }
        }

        return $array ;
    }
}<file_sep><?php

namespace Pythagus\Lydia\Exceptions;

use Pythagus\Lydia\Contracts\LydiaException;

/**
 * Class LydiaErrorResponseException
 * @package Pythagus\Lydia\Exceptions
 *
 * @property int    code
 * @property string message
 *
 * @author: <NAME>
 */
class LydiaErrorResponseException extends LydiaException {

    /**
     * Lydia error code.
     *
     * @var integer
     */
    public $code ;

    /**
     * The returned message.
     *
     * @var string
     */
    public $message ;

    /**
     * Make a new error exception.
     *
     * @param string $message : original exception message.
     * @param array $response
     */
    public function __construct(int $code, string $message) {
        $this->code    = $code ;
        $this->message = $message ;

        parent::__construct("$message (code $code)") ;
    }
}<file_sep><?php

namespace Pythagus\Lydia;

use Exception;
use Pythagus\Lydia\Traits\HasConfig;
use Pythagus\Lydia\Contracts\LydiaState;

/**
 * Class Lydia
 * @package Pythagus\Lydia
 *
 * @author: <NAME>
 */
class Lydia implements LydiaState {

    use HasConfig ;

    /**
     * The current globally available container (if any).
     *
     * @var Lydia
     */
    protected static $instance ;

    public function __construct() {
        $this->configs = $this->setConfigArray() ;
    }

    /**
     * Set the Lydia instance.
     *
     * @param Lydia $lydia
     */
    public static function setInstance(Lydia $lydia) {
        Lydia::$instance = $lydia ;
    }

    /**
     * Get the globally available instance of the Lydia
     * facade.
     *
     * @return static
     */
    public static function getInstance() {
        if(empty(Lydia::$instance)) {
            Lydia::$instance = new static ;
        }

        return Lydia::$instance ;
    }

    /**
     * Get the Lydia's configuration.
     *
     * @return array
     */
    protected function setConfigArray() {
        return [] ;
    }

    /**
     * Redirect the user to the given route.
     *
     * @param string $route
     * @return mixed
     */
    public function redirect(string $route) {
        header('Location: '.$route) ;
        exit() ;
    }

    /**
     * Format the callback URL to be valid
     * regarding the Lydia server.
     *
     * @param string $url
     * @return string
     */
    public function formatCallbackUrl(string $url) {
        throw new Exception("Should override this method") ;
    }
}<file_sep><?php

return [

	/*
	|--------------------------------------------------------------------------
	| Lydia main properties
	|--------------------------------------------------------------------------
	|
	| This array lists the properties that won't change
	| from a request to another. This properties are added
	| in the LydiaRequest.executeRequest() method.
	*/
	'properties' => [
		// Currency: only EUR and GBP are supported.
		'currency' => 'EUR',
	],

	/*
	|--------------------------------------------------------------------------
	| Lydia debugging mode
	|--------------------------------------------------------------------------
	|
	| This value determines whether the website is in a debugging mode.
	| The transactions won't be move money.
	*/
	'debug' => true,

	/*
	|--------------------------------------------------------------------------
	| Lydia credentials
	|--------------------------------------------------------------------------
	|
	| This array contains the different PaymentLydia's credentials according
	| to the previous debug value.
	*/
	'credentials' => [
		/*
		 * Debugging mode.
		 */
		'debug' => [
			'url_server'    => 'https://homologation.lydia-app.com',
			'vendor_token'  => "<PASSWORD>",
			'private_token' => "<PASSWORD>",
		],

		/*
		 * Production mode.
		 */
		'prod'  => [
			'url_server'    => 'https://lydia-app.com',
			'vendor_token'  => "<PASSWORD>",
			'private_token' => "<PASSWORD>",
		],
	],

	/*
	|--------------------------------------------------------------------------
	| Lydia's URL
	|--------------------------------------------------------------------------
	|
	| This array contains the available and used Lydia's url
	*/
	'url' => [
		/*
		 * URL used to make transactions.
		 */
		'do' => '/api/request/do.json',

		/*
		 * URL used to check the payment state.
		 */
		'state' => '/api/request/state.json',

		/*
		 * URL used to refund transaction. This
		 * route is sometimes comment to be unusable.
		 */
		'refund' => '/api/transaction/refund.json',
	],

] ;
<file_sep><?php

namespace Pythagus\Lydia\Http;

use Pythagus\Lydia\Lydia;
use Pythagus\Lydia\Contracts\LydiaException;
use Pythagus\Lydia\Exceptions\LydiaErrorResponseException;

/**
 * Class PaymentRequest
 * @package Pythagus\Lydia\Http
 *
 * @property string url
 *
 * @author: <NAME>
 */
class PaymentRequest extends LydiaRequest {

    /**
     * Redirection url.
     *
     * @var string
     */
    protected $url ;

    /**
     * Execute the request.
     *
     * @return mixed
     * @throws LydiaException
     */
    protected function run() {
        $result = $this->requestServer('do') ;

        // If there is an error, then throw an exception.
        if($result['error'] != 0) {
            throw new LydiaErrorResponseException(
                intval($result['error']), $result['message']
            ) ;
        }

        /**
         * This method prevents to the Lydia problems that
         * can occurred. The incoming exception should not
         * be caught here to be printed to the client.
         *
         * @throws LydiaException
         */
        $this->lydiaResponseContains($result, [
            'error', 'mobile_url', 'request_uuid', 'request_id'
        ], true) ;

        /*
         * Here, the response should be a Std object
         * with keys:
         * - error: Set to 0 if there is no error.
         * - request_id: id of the request. You may need it to cancel the request.
         * - request_uuid: UUID of the request. You may need it to check the request sate.
         * - message: State of the request.
         * - mobile_url: An url where you can redirect your user to let them pay. Lydia will
         *   handle if they already have an account or show the a credit card payment form.
         * - order_ref: Only if an order_ref was specified.
         */
        $this->url = $result['mobile_url'] ;

        return [
            'state'        => Lydia::WAITING_PAYMENT,
            'url'          => $this->url,
            'request_id'   => $result['request_id'],
            'request_uuid' => $result['request_uuid'],
        ] ;
    }

    /**
     * Get the list of required parameters for
     * the request.
     *
     * @return array
     */
    protected function shouldHaveParameters() {
        return ['recipient', 'amount'] ;
    }

    /**
     * Set the default parameters.
     *
     * @return void
     */
    protected function setDefaultParameters() {
        /*
         * Vendor token of the business that done the request
         * (if it's a request for a business)
         */
        $this->setParameter('vendor_token', $this->getLydiaVendorToken()) ;

        // recipient type - Allowed values: email, phone
        $this->setParameter('type', 'email') ;

        /*
         * Skip the Lydia confirmation page if browser_success_url is
         * also set. This parameter is optional, accepted values are "yes" and "no",
         * default is "yes".
         */
        $this->setParameter('display_confirmation', 'no') ;

        /*
         * Defines how the payment should be made: 'lydia' send a payment request to the lydia
         * user's phone or send him to a download page if he doesn't have the app. 'cb' redirect
         * the user to a classic credit card payment form. 'auto' either 'lydia' or 'cb' depending
         * on whether or not a lydia account is associated with this mobile number
         */
        $this->setParameter('payment_method', 'cb') ;

        // the payer of the payment request by SMS
        $this->setParameter('notify', 'no') ;

        // send an email to the business owner when the request is accepted by the payer
        $this->setParameter('notify_collector', 'no') ;

        /*
         * duration in seconds after which the payment request becomes invalid. This duration can't
         * exceed 7 days (604 800). If the value is up to 604800, the request will automatically
         * expire on the 7th day.
         */
        $this->setParameter('expire_time', '600') ;
    }

    /**
     * Redirect the client to the Lydia website.
     *
     * @return mixed
     * @throws LydiaException
     */
    public function redirect() {
        if(is_null($this->url)) {
            throw new LydiaException("Impossible to redirect to Lydia's server") ;
        }

        return $this->lydia()->redirect($this->url) ;
    }

    /**
     * Set the callback when the user is redirected.
     *
     * @param string $url
     */
    public function setFinishCallback(string $url) {
        $route = $this->formatCallbackUrl($url) ;

        $this->setParameter('confirm_url', $route) ;
        $this->setParameter('cancel_url', $route) ;
        $this->setParameter('end_mobile_url', $route) ;
        $this->setParameter('browser_success_url', $route) ;
        $this->setParameter('browser_fail_url', $route) ;
    }

    /**
     * Format the callback URL to be valid
     * regarding the Lydia server.
     *
     * @param string $url
     * @return string
     */
    private function formatCallbackUrl(string $url) {
        return $this->lydia()->formatCallbackUrl($url) ;
    }
}