-
-
Notifications
You must be signed in to change notification settings - Fork 73
Fixes #39 Fixes #40 remove laminas-loader dependency #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
06cab9d
456d1ac
6c14e97
c1a60d8
1cb61e3
751f035
b6fdc6e
ba55363
c80ca31
a044a40
a99f2d5
ea80330
56df540
8e286c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * @see https://github.com/laminas/laminas-mail for the canonical source repository | ||
| * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md | ||
| * @license https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Laminas\Mail\Header; | ||
|
|
||
| /** | ||
| * Plugin Class Loader implementation for HTTP headers | ||
| */ | ||
| final class HeaderLocator implements HeaderLocatorInterface | ||
| { | ||
| /** | ||
| * @var array Pre-aliased Header plugins | ||
| */ | ||
| private $plugins = [ | ||
| 'bcc' => Bcc::class, | ||
| 'cc' => Cc::class, | ||
| 'contentdisposition' => ContentDisposition::class, | ||
| 'content_disposition' => ContentDisposition::class, | ||
| 'content-disposition' => ContentDisposition::class, | ||
| 'contenttype' => ContentType::class, | ||
| 'content_type' => ContentType::class, | ||
| 'content-type' => ContentType::class, | ||
| 'contenttransferencoding' => ContentTransferEncoding::class, | ||
| 'content_transfer_encoding' => ContentTransferEncoding::class, | ||
| 'content-transfer-encoding' => ContentTransferEncoding::class, | ||
| 'date' => Date::class, | ||
| 'from' => From::class, | ||
| 'in-reply-to' => InReplyTo::class, | ||
| 'message-id' => MessageId::class, | ||
| 'mimeversion' => MimeVersion::class, | ||
| 'mime_version' => MimeVersion::class, | ||
| 'mime-version' => MimeVersion::class, | ||
| 'received' => Received::class, | ||
| 'references' => References::class, | ||
| 'replyto' => ReplyTo::class, | ||
| 'reply_to' => ReplyTo::class, | ||
| 'reply-to' => ReplyTo::class, | ||
| 'sender' => Sender::class, | ||
| 'subject' => Subject::class, | ||
| 'to' => To::class, | ||
| ]; | ||
|
|
||
| public function get(string $name, ?string $default = null): ?string | ||
| { | ||
| $name = $this->normalizeName($name); | ||
| return isset($this->plugins[$name]) ? $this->plugins[$name] : $default; | ||
| } | ||
|
|
||
| public function has(string $name): bool | ||
| { | ||
| return isset($this->plugins[$this->normalizeName($name)]); | ||
| } | ||
|
|
||
| public function add(string $name, string $class): void | ||
| { | ||
| $this->plugins[$this->normalizeName($name)] = $class; | ||
| } | ||
|
|
||
| public function remove(string $name): void | ||
| { | ||
| unset($this->plugins[$this->normalizeName($name)]); | ||
| } | ||
|
|
||
| private function normalizeName(string $name): string | ||
| { | ||
| return strtolower($name); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * @see https://github.com/laminas/laminas-mail for the canonical source repository | ||
| * @copyright https://github.com/laminas/laminas-mail/blob/master/COPYRIGHT.md | ||
| * @license https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Laminas\Mail\Header; | ||
|
|
||
| /** | ||
| * Interface detailing how to resolve header names to classes. | ||
| */ | ||
| interface HeaderLocatorInterface | ||
| { | ||
| public function get(string $name, ?string $default = null): ?string; | ||
|
|
||
| public function has(string $name): bool; | ||
|
|
||
| public function add(string $name, string $class): void; | ||
|
|
||
| public function remove(string $name): void; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,11 +6,14 @@ | |
| * @license https://github.com/laminas/laminas-mail/blob/master/LICENSE.md New BSD License | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Laminas\Mail; | ||
|
|
||
| use ArrayIterator; | ||
| use Countable; | ||
| use Iterator; | ||
| use Laminas\Loader\PluginClassLoader; | ||
| use Laminas\Loader\PluginClassLocator; | ||
| use Laminas\Mail\Header\GenericHeader; | ||
| use Laminas\Mail\Header\HeaderInterface; | ||
|
|
@@ -30,9 +33,15 @@ class Headers implements Countable, Iterator | |
| const FOLDING = "\r\n "; | ||
|
|
||
| /** | ||
| * @var \Laminas\Loader\PluginClassLoader | ||
| * @var null|Header\HeaderLocatorInterface | ||
| */ | ||
| protected $pluginClassLoader = null; | ||
| private $headerLocator; | ||
|
|
||
| /** | ||
| * @todo Remove for 3.0.0. | ||
| * @var null|PluginClassLocator | ||
| */ | ||
| protected $pluginClassLoader; | ||
|
|
||
| /** | ||
| * @var array key names for $headers array | ||
|
|
@@ -119,30 +128,73 @@ public static function fromString($string, $EOL = self::EOL) | |
| } | ||
|
|
||
| /** | ||
| * Set an alternate implementation for the PluginClassLoader | ||
| * Set an alternate PluginClassLocator implementation for loading header classes. | ||
| * | ||
| * @param PluginClassLocator $pluginClassLoader | ||
| * @return Headers | ||
| * @deprecated since 2.12.0 | ||
| * @todo Remove for version 3.0.0 | ||
| * @return $this | ||
| */ | ||
| public function setPluginClassLoader(PluginClassLocator $pluginClassLoader) | ||
| { | ||
| // Silenced; can be caught in custom error handlers. | ||
| @trigger_error(sprintf( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As @glensc pointed out, this is how Symfony does deprecation notices. They'll get caught in error handlers, but not if unhandled. This prevents breakage in most use cases, but if you log errors, you'll catch them in your logs. |
||
| 'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::setHeaderLocator() instead', | ||
| __METHOD__, | ||
| __CLASS__ | ||
| ), E_USER_DEPRECATED); | ||
|
|
||
| $this->pluginClassLoader = $pluginClassLoader; | ||
| return $this; | ||
| } | ||
|
|
||
| /** | ||
| * Return an instance of a PluginClassLocator, lazyload and inject map if necessary | ||
| * Return a PluginClassLocator instance for customizing headers. | ||
| * | ||
| * Lazyloads a Header\HeaderLoader if necessary. | ||
| * | ||
| * @deprecated since 2.12.0 | ||
| * @todo Remove for version 3.0.0 | ||
| * @return PluginClassLocator | ||
| */ | ||
| public function getPluginClassLoader() | ||
| { | ||
| if ($this->pluginClassLoader === null) { | ||
| // Silenced; can be caught in custom error handlers. | ||
| @trigger_error(sprintf( | ||
| 'Since laminas/laminas-mail 2.12.0: Usage of %s is deprecated; use %s::getHeaderLocator() instead', | ||
| __METHOD__, | ||
| __CLASS__ | ||
| ), E_USER_DEPRECATED); | ||
|
|
||
| if (! $this->pluginClassLoader) { | ||
| $this->pluginClassLoader = new Header\HeaderLoader(); | ||
| } | ||
|
|
||
| return $this->pluginClassLoader; | ||
| } | ||
|
|
||
| /** | ||
| * Retrieve the header class locator for customizing headers. | ||
| * | ||
| * Lazyloads a Header\HeaderLocator instance if necessary. | ||
| */ | ||
| public function getHeaderLocator(): Header\HeaderLocatorInterface | ||
| { | ||
| if (! $this->headerLocator) { | ||
| $this->setHeaderLocator(new Header\HeaderLocator()); | ||
| } | ||
| return $this->headerLocator; | ||
| } | ||
|
|
||
| /** | ||
| * @todo Return self when we update to 7.4 or later as minimum PHP version. | ||
| * @return $this | ||
| */ | ||
| public function setHeaderLocator(Header\HeaderLocatorInterface $headerLocator) | ||
| { | ||
| $this->headerLocator = $headerLocator; | ||
| return $this; | ||
| } | ||
|
|
||
| /** | ||
| * Set the header encoding | ||
| * | ||
|
|
@@ -270,9 +322,20 @@ public function addHeader(Header\HeaderInterface $header) | |
| */ | ||
| public function removeHeader($instanceOrFieldName) | ||
| { | ||
| if (! $instanceOrFieldName instanceof Header\HeaderInterface && ! is_string($instanceOrFieldName)) { | ||
| throw new Exception\InvalidArgumentException(sprintf( | ||
| '%s requires a string or %s instance; received %s', | ||
| __METHOD__, | ||
| Header\HeaderInterface::class, | ||
| is_object($instanceOrFieldName) ? get_class($instanceOrFieldName) : gettype($instanceOrFieldName) | ||
| )); | ||
| } | ||
|
Comment on lines
+325
to
+332
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This bit was interesting. Because I turned on strict types in this file, I discovered a test that was passing |
||
|
|
||
| if ($instanceOrFieldName instanceof Header\HeaderInterface) { | ||
| $indexes = array_keys($this->headers, $instanceOrFieldName, true); | ||
| } else { | ||
| } | ||
|
|
||
| if (is_string($instanceOrFieldName)) { | ||
| $key = $this->normalizeFieldName($instanceOrFieldName); | ||
| $indexes = array_keys($this->headersKeys, $key, true); | ||
| } | ||
|
|
@@ -481,7 +544,7 @@ public function loadHeader($headerLine) | |
| list($name, ) = Header\GenericHeader::splitHeaderLine($headerLine); | ||
|
|
||
| /** @var HeaderInterface $class */ | ||
| $class = $this->getPluginClassLoader()->load($name) ?: Header\GenericHeader::class; | ||
| $class = $this->resolveHeaderClass($name); | ||
| return $class::fromString($headerLine); | ||
| } | ||
|
|
||
|
|
@@ -496,7 +559,7 @@ protected function lazyLoadHeader($index) | |
| $key = $this->headersKeys[$index]; | ||
|
|
||
| /** @var GenericHeader $class */ | ||
| $class = ($this->getPluginClassLoader()->load($key)) ?: Header\GenericHeader::class; | ||
| $class = $this->resolveHeaderClass($key); | ||
|
|
||
| $encoding = $current->getEncoding(); | ||
| $headers = $class::fromString($current->toString()); | ||
|
|
@@ -528,4 +591,16 @@ protected function normalizeFieldName($fieldName) | |
| { | ||
| return str_replace(['-', '_', ' ', '.'], '', strtolower($fieldName)); | ||
| } | ||
|
|
||
| /** | ||
| * @param string $key | ||
| * @return string | ||
| */ | ||
| private function resolveHeaderClass($key) | ||
| { | ||
| if ($this->pluginClassLoader) { | ||
| return $this->pluginClassLoader->load($key) ?: Header\GenericHeader::class; | ||
| } | ||
| return $this->getHeaderLocator()->get($key, Header\GenericHeader::class); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are why I lumped the bump in PHP version into the patch: scalar type hints, return type hints, nullable types, and void return types. Essentially it is this patch that necessitates the bump in minimum version, which is exactly what the TSC decision was about in that first meeting. 😄