Client Incomptabile with PHP Scoper
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
- Use PHP Scoper to add a unique namespace to the package
- 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:
- sendgrid-php version: 7.8.4
- php version: 7.4
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.
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;
},
],
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.