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..