
Fermin Perdomo
Full Stack Developer

Handling Deprecated Methods in Third-Party PHP Libraries: My PayPal Integration Journey
I was working on a PayPal integration when I ran into an issue caused by a deprecated method in a third-party library.
Big thanks to Elminson De Oleo Baez from the PHP Dominicana community for writing the article Trait and Classes Hacking: Customizing Package Libraries with PHP Traits and Classes. It gave me a solid idea of how to move forward.
However, I hit another roadblock: the package used a trait within a trait, which made it tricky to override the deprecated method. So, I decided to take a different route—I created my client version of the third-party library and built a custom trait that replaced the deprecated functions.
So I started creating my Paypal service:
namespace App\Extension\Paypal\Services;
use App\Extension\Paypal\Traits\PayPalAPI;
use App\Extension\Paypal\Traits\PayPalExperienceContext;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Exception\ClientException as HttpClientException;
use GuzzleHttp\Utils;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use Srmklive\PayPal\Services\Str;
use Srmklive\PayPal\Traits\PayPalVerifyIPN;
class Paypal
{
use PayPalAPI;
use PayPalExperienceContext;
use PayPalVerifyIPN;
/**
* Http Client class object.
*
* @var HttpClient
*/
private $client;
/**
* Http Client configuration.
*
* @var array
*/
private $httpClientConfig;
/**
* PayPal API Endpoint.
*
* @var string
*/
private $apiUrl;
/**
* PayPal API Endpoint.
*
* @var string
*/
private $apiEndPoint;
/**
* IPN notification url for PayPal.
*
* @var string
*/
private $notifyUrl;
/**
* Http Client request body parameter name.
*
* @var string
*/
private $httpBodyParam;
/**
* Default payment action for PayPal.
*
* @var string
*/
private $paymentAction;
/**
* Default locale for PayPal.
*
* @var string
*/
private $locale;
/**
* Validate SSL details when creating HTTP client.
*
* @var bool
*/
private $validateSSL;
/**
* Request type.
*
* @var string
*/
protected $verb = 'post';
/**
* PayPal API mode to be used.
*
* @var string
*/
public $mode;
/**
* PayPal access token.
*
* @var string
*/
protected $access_token;
/**
* PayPal API configuration.
*
* @var array
*/
private array $config;
/**
* Default currency for PayPal.
*
* @var string
*/
protected $currency;
/**
* Additional options for PayPal API request.
*
* @var array
*/
protected $options;
/**
* Set limit to total records per API call.
*
* @var int
*/
protected $page_size = 20;
/**
* Set the current page for list resources API calls.
*
* @var bool
*/
protected $current_page = 1;
/**
* Toggle whether totals for list resources are returned after every API call.
*
* @var string
*/
protected string $show_totals;
/**
* PayPal constructor.
*
* @param array $config
*
* @throws Exception
*/
public function __construct(array $config = [])
{
// Setting PayPal API Credentials
$this->setConfig($config);
$this->httpBodyParam = 'form_params';
$this->options = [];
$this->setRequestHeader('Accept', 'application/json');
}
}
Then I have to move all the methods that need to be overwrite to my custom service class:
namespace App\Extension\Paypal\Services;
use App\Extension\Paypal\Traits\PayPalAPI;
use App\Extension\Paypal\Traits\PayPalExperienceContext;
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Exception\ClientException as HttpClientException;
use GuzzleHttp\Utils;
use Psr\Http\Message\StreamInterface;
use RuntimeException;
use Srmklive\PayPal\Services\Str;
use Srmklive\PayPal\Traits\PayPalVerifyIPN;
class Paypal
{
use PayPalAPI;
use PayPalExperienceContext;
use PayPalVerifyIPN;
/**
* Http Client class object.
*
* @var HttpClient
*/
private $client;
/**
* Http Client configuration.
*
* @var array
*/
private $httpClientConfig;
/**
* PayPal API Endpoint.
*
* @var string
*/
private $apiUrl;
/**
* PayPal API Endpoint.
*
* @var string
*/
private $apiEndPoint;
/**
* IPN notification url for PayPal.
*
* @var string
*/
private $notifyUrl;
/**
* Http Client request body parameter name.
*
* @var string
*/
private $httpBodyParam;
/**
* Default payment action for PayPal.
*
* @var string
*/
private $paymentAction;
/**
* Default locale for PayPal.
*
* @var string
*/
private $locale;
/**
* Validate SSL details when creating HTTP client.
*
* @var bool
*/
private $validateSSL;
/**
* Request type.
*
* @var string
*/
protected $verb = 'post';
/**
* PayPal API mode to be used.
*
* @var string
*/
public $mode;
/**
* PayPal access token.
*
* @var string
*/
protected $access_token;
/**
* PayPal API configuration.
*
* @var array
*/
private array $config;
/**
* Default currency for PayPal.
*
* @var string
*/
protected $currency;
/**
* Additional options for PayPal API request.
*
* @var array
*/
protected $options;
/**
* Set limit to total records per API call.
*
* @var int
*/
protected $page_size = 20;
/**
* Set the current page for list resources API calls.
*
* @var bool
*/
protected $current_page = 1;
/**
* Toggle whether totals for list resources are returned after every API call.
*
* @var string
*/
protected string $show_totals;
/**
* PayPal constructor.
*
* @param array $config
*
* @throws Exception
*/
public function __construct(array $config = [])
{
// Setting PayPal API Credentials
$this->setConfig($config);
$this->httpBodyParam = 'form_params';
$this->options = [];
$this->setRequestHeader('Accept', 'application/json');
}
/**
* Set ExpressCheckout API endpoints & options.
*
* @param array $credentials
*/
protected function setOptions(array $credentials): void
{
// Setting API Endpoints
$this->config['api_url'] = 'https://api-m.paypal.com';
$this->config['gateway_url'] = 'https://www.paypal.com';
$this->config['ipn_url'] = 'https://ipnpb.paypal.com/cgi-bin/webscr';
if ($this->mode === 'sandbox') {
$this->config['api_url'] = 'https://api-m.sandbox.paypal.com';
$this->config['gateway_url'] = 'https://www.sandbox.paypal.com';
$this->config['ipn_url'] = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
}
// Adding params outside sandbox / live array
$this->config['payment_action'] = $credentials['payment_action'];
$this->config['notify_url'] = $credentials['notify_url'];
$this->config['locale'] = $credentials['locale'];
}
/**
* Login through PayPal API to get access token.
*
* @throws \Throwable
*
* @return array|\Psr\Http\Message\StreamInterface|string
*
* @see https://developer.paypal.com/docs/api/get-an-access-token-curl/
* @see https://developer.paypal.com/docs/api/get-an-access-token-postman/
*/
public function getAccessToken()
{
$this->apiEndPoint = 'v1/oauth2/token';
$this->options['auth'] = [$this->config['client_id'], $this->config['client_secret']];
$this->options[$this->httpBodyParam] = [
'grant_type' => 'client_credentials',
];
$response = $this->doPayPalRequest();
unset($this->options['auth']);
unset($this->options[$this->httpBodyParam]);
if (isset($response['access_token'])) {
$this->setAccessToken($response);
}
return $response;
}
// others method
}
To view the complete version of this class, you can refer to the PayPalService gist. To explore the other custom traits, check the full gist here..