sendgrid / sendgrid-php

The Official Twilio SendGrid PHP API Library
https://sendgrid.com
MIT License
1.49k stars 623 forks source link

Client Incomptabile with PHP Scoper #1010

Open bartboy011 opened 4 years ago

bartboy011 commented 4 years ago

Issue Summary

PHP Scoper is a tool that adds a unique prefix to all namespaces in the vendor directory of a project in order to prevent namespace collisions - for example, if I'm developing a wordpress plugin and want to avoid namespace collisions or version collisions with the dependencies of other wordpress plugins, I'll use Scoper.

In lib/mail/Mail.php there is this line: https://github.com/sendgrid/sendgrid-php/blob/7bdf97e961f0eb529a0a027ae7d3b8a204faa905/lib/mail/Mail.php#L188. PHP Scoper is not able to detect dynamic class names like this, and so the prefix is not applied.

If using Scoper, the logic in that block fails and a fatal exception is raised. This effectively looks like:

$email = new \MyScopedNamespace\SendGrid\Mail\Mail();

// the logic from the link above
$emailTypeClass = '\SendGrid\\Mail\\' . $emailType; // '\SendGrid\Mail\Mail'
if (!$email instanceof $emailTypeClass) { // If not '\MyScopedNamespace\SendGrid\Mail\Mail' instance of '\SendGrid\Mail\Mail'
    $email = new $emailTypeClass($email, $name, $substitutions); // because of the prefixed namespace, '\SendGrid\Mail\Mail' does not exist
}

There is a workaround for this issue: https://github.com/humbug/php-scoper#patchers. This workaround is less than ideal as it's highly manual.

Steps to Reproduce

  1. Use PHP Scoper to add a unique namespace to the package
  2. Attempt to send an email using that namespaced package

Code Snippet

# paste code here

Exception/Log

2020-10-04T14:39:50+00:00 CRITICAL Uncaught Error: Object of class \Vendor\SendGrid\Mail\To could not be converted to string in /www/mysite/public/vendor/sendgrid/sendgrid/lib/helper/Assert.php:28
Stack trace:
#0 /www/mysite/public/vendor/sendgrid/sendgrid/lib/helper/Assert.php(28): sprintf('"$%s" must be a...', 'emailAddress', Object(\Vendor\SendGrid\Mail\To))
#1 /www/mysite/public/vendor/sendgrid/sendgrid/lib/helper/Assert.php(48): SendGrid\Helper\Assert::string(Object(\Vendor\SendGrid\Mail\To), 'emailAddress', NULL)
#2 /www/mysite/public/vendor/sendgrid/sendgrid/lib/mail/EmailAddress.php(69): SendGrid\Helper\Assert::email(Object(\Vendor\SendGrid\Mail\To), 'emailAddress')
#3 /www/mysite/public/vendor/sendgrid/sendgrid/lib/mail/EmailAddress.php(47): SendGrid\Mail\EmailAddress->setEmailAddress(Object(\Vendor\SendGrid\Mail\To))
#4 /www/mysite/public/build/sendgrid/sendgrid/lib/mail/Mail.php(148): SendGrid\Mail\EmailAddress->__construct(Objec in /www/mysite/public/vendor/sendgrid/sendgrid/lib/helper/Assert.php on line 28

Technical details:

bartboy011 commented 4 years ago

Note - in my error logs, a class not found fatal is not raised as my code is running in a WordPress environment where other plugins have loaded their own versions of the SendGrid client.

bartboy011 commented 4 years ago

For anyone who comes across this, adding this code block to your scoper.inc.php should correct the issue:

'patchers' => [
    function (string $filePath, string $prefix, string $content): string {
        if ($filePath === '/path/to/my/project/vendor/sendgrid/sendgrid/lib/mail/Mail.php') {
            $replacement = str_replace(
                '\\\\SendGrid\\\\Mail\\\\',
                $prefix . '\\\\SendGrid\\\\Mail\\\\',
                $content
            );

            if ($replacement !== null) {
                return $replacement;
            }
        }
        return $content;
    },
],
childish-sambino commented 4 years ago

This issue has been added to our internal backlog to be prioritized. Pull requests and +1s on the issue summary will help it move up the backlog.