Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ All notable changes to this project will be documented in this file, in reverse

### Added

- [#95](https://github.com/laminas/laminas-mail/pull/95) adds the methods `setHeaderLoader(Header\HeaderLoader $loader)` and `getHeaderLoader()` to the `Headers` implementation. Users are encouraged to use these if they need access to the header class lazy-loader.

- [#94](https://github.com/laminas/laminas-mail/pull/94) adds the "novalidatecert" option for POP3 and IMAP connections. When toggled true, you can connect to servers using self-signed certificates.

### Changed

- Nothing.
- [#95](https://github.com/laminas/laminas-mail/pull/95) modifies `Laminas\Header\HeaderLoader` to no longer extend `Laminas\Loader\PluginClassLoader`.

### Deprecated

- Nothing.
- [#95](https://github.com/laminas/laminas-mail/pull/95) deprecates the `Headers::getPluginClassLoader()` and `Headers::setPluginClassLoader()` methods, in favor of the new `setHeaderLoader()` and `getHeaderLoader()` methods. These methods will be removed in version 3.0.0, and laminas-loader `PluginClassLocator` instances will no longer be supported.

### Removed

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"require": {
"php": "^5.6 || ^7.0",
"ext-iconv": "*",
"laminas/laminas-loader": "^2.5",
"laminas/laminas-mime": "^2.5",
"laminas/laminas-stdlib": "^2.7 || ^3.0",
"laminas/laminas-validator": "^2.10.2",
Expand All @@ -55,6 +54,9 @@
}
},
"autoload-dev": {
"files": [
"test/TestAsset/PluginClassLocator.php"
],
"psr-4": {
"LaminasTest\\Mail\\": "test/"
}
Expand Down
39 changes: 36 additions & 3 deletions src/Header/HeaderLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@

namespace Laminas\Mail\Header;

use Laminas\Loader\PluginClassLoader;

/**
* Plugin Class Loader implementation for HTTP headers
*/
class HeaderLoader extends PluginClassLoader
class HeaderLoader
{
/**
* @var array Pre-aliased Header plugins
Expand Down Expand Up @@ -46,4 +44,39 @@ class HeaderLoader extends PluginClassLoader
'subject' => Subject::class,
'to' => To::class,
];

/**
* @param string $name
* @param string|null $default
* @return string|null
*/
public function get($name, $default = null)
{
$name = $this->normalizeName($name);
return isset($this->plugins[$name]) ? $this->plugins[$name] : $default;
}

/**
* @param string $name
* @return bool
*/
public function has($name)
{
return isset($this->plugins[$this->normalizeName($name)]);
}

public function add($name, $class)
{
$this->plugins[$this->normalizeName($name)] = $class;
}

public function remove($name)
{
unset($this->plugins[$this->normalizeName($name)]);
}

private function normalizeName($name)
{
return strtolower($name);
}
}
71 changes: 63 additions & 8 deletions src/Headers.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use ArrayIterator;
use Countable;
use Iterator;
use Laminas\Loader\PluginClassLoader;
use Laminas\Loader\PluginClassLocator;
use Laminas\Mail\Header\GenericHeader;
use Laminas\Mail\Header\HeaderInterface;
Expand All @@ -30,7 +31,9 @@ class Headers implements Countable, Iterator
const FOLDING = "\r\n ";

/**
* @var \Laminas\Loader\PluginClassLoader
* @todo Rename to $headerLoader for 3.0.0
* @todo Remove ability to use PluginClassLoader for 3.0.0
* @var null|Header\HeaderLoader|PluginClassLoader
*/
protected $pluginClassLoader = null;

Expand Down Expand Up @@ -119,30 +122,73 @@ public static function fromString($string, $EOL = self::EOL)
}

/**
* Set an alternate implementation for the PluginClassLoader
* Set an alternate implementation for loading header classes.
*
* @param PluginClassLocator $pluginClassLoader
* @deprecated since 2.12.0
* @todo Remove for version 3.0.0
* @param Header\HeaderLoader|\Laminas\Loader\PluginClassLocator $pluginClassLoader
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Laminas\Loader\PluginClassLocator can be changed with PluginClassLocator as the class re-added to use statement.

* @return Headers
*/
public function setPluginClassLoader(PluginClassLocator $pluginClassLoader)
public function setPluginClassLoader($pluginClassLoader)
{
if ($pluginClassLoader instanceof PluginClassLocator) {
trigger_error(sprintf(
'Usage of %s instances for loading headers has been deprecated; please use %s',
PluginClassLoader::class,
Header\HeaderLoader::class
), E_USER_DEPRECATED);
}

$this->pluginClassLoader = $pluginClassLoader;
return $this;
}

/**
* Return an instance of a PluginClassLocator, lazyload and inject map if necessary
* Return an instance of a Header\HeaderLoader or PluginClassLocator
*
* @return PluginClassLocator
* Lazyloads a Header\HeaderLoader if necessary.
*
* @deprecated since 2.12.0
* @todo Remove for version 3.0.0
* @return Header\HeaderLoader|PluginClassLocator
*/
public function getPluginClassLoader()
{
trigger_error(sprintf(
'The method %s has been deprecated; please use getHeaderLoader() or resolveHeaderClass() instead',
__METHOD__
), E_USER_DEPRECATED);

if ($this->pluginClassLoader === null) {
$this->pluginClassLoader = new Header\HeaderLoader();
}

return $this->pluginClassLoader;
}

/**
* Retrieve the header class loader.
*
* @todo remove ability to return PluginClassLoader for 3.0.0
* @return Header\HeaderLoader|PluginClassLoader
*/
public function getHeaderLoader()
{
if (! $this->pluginClassLoader) {
$this->setHeaderLoader(new Header\HeaderLoader());
}
return $this->pluginClassLoader;
}

/**
* @return $this
*/
public function setHeaderLoader(Header\HeaderLoader $headerLoader)
{
$this->pluginClassLoader = $headerLoader;
return $this;
}

/**
* Set the header encoding
*
Expand Down Expand Up @@ -481,7 +527,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);
}

Expand All @@ -496,7 +542,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());
Expand Down Expand Up @@ -528,4 +574,13 @@ protected function normalizeFieldName($fieldName)
{
return str_replace(['-', '_', ' ', '.'], '', strtolower($fieldName));
}

/**
* @param string $key
* @return string
*/
private function resolveHeaderClass($key)
{
return $this->getHeaderLoader()->get($key, Header\GenericHeader::class);
}
}
102 changes: 102 additions & 0 deletions test/Header/HeaderLoaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?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
*/

namespace LaminasTest\Mail\Header;

use PHPUnit\Framework\TestCase;
use Laminas\Mail\Header;

class HeaderLoaderTest extends TestCase
{
/**
* @var Header\HeaderLoader
*/
private $headerLoader;

public function setUp()
{
$this->headerLoader = new Header\HeaderLoader();
}

public function provideHeaderNames()
{
return [
'with existing name' => ['to', Header\To::class],
'with non-existent name' => ['foo', null],
'with default value' => ['foo', Header\GenericHeader::class, Header\GenericHeader::class],
];
}

/**
* @param $name
* @param $expected
* @param $default
* @dataProvider provideHeaderNames
*/
public function testHeaderIsProperlyLoaded($name, $expected, $default = null)
{
$this->assertEquals($expected, $this->headerLoader->get($name, $default));
}

public function testHeaderExistenceIsProperlyChecked()
{
$this->assertTrue($this->headerLoader->has('to'));
$this->assertTrue($this->headerLoader->has('To'));
$this->assertTrue($this->headerLoader->has('Reply_to'));
$this->assertTrue($this->headerLoader->has('SUBJECT'));
$this->assertFalse($this->headerLoader->has('foo'));
$this->assertFalse($this->headerLoader->has('bar'));
}

public function testHeaderCanBeAdded()
{
$this->assertFalse($this->headerLoader->has('foo'));
$this->headerLoader->add('foo', Header\GenericHeader::class);
$this->assertTrue($this->headerLoader->has('foo'));
}

public function testHeaderCanBeRemoved()
{
$this->assertTrue($this->headerLoader->has('to'));
$this->headerLoader->remove('to');
$this->assertFalse($this->headerLoader->has('to'));
}

public static function expectedHeaders()
{
return [
'bcc' => ['bcc', Header\Bcc::class],
'cc' => ['cc', Header\Cc::class],
'contenttype' => ['contenttype', Header\ContentType::class],
'content_type' => ['content_type', Header\ContentType::class],
'content-type' => ['content-type', Header\ContentType::class],
'date' => ['date', Header\Date::class],
'from' => ['from', Header\From::class],
'mimeversion' => ['mimeversion', Header\MimeVersion::class],
'mime_version' => ['mime_version', Header\MimeVersion::class],
'mime-version' => ['mime-version', Header\MimeVersion::class],
'received' => ['received', Header\Received::class],
'replyto' => ['replyto', Header\ReplyTo::class],
'reply_to' => ['reply_to', Header\ReplyTo::class],
'reply-to' => ['reply-to', Header\ReplyTo::class],
'sender' => ['sender', Header\Sender::class],
'subject' => ['subject', Header\Subject::class],
'to' => ['to', Header\To::class],
];
}

/**
* @dataProvider expectedHeaders
* @param string $name
* @param Header\HeaderInterface $class
*/
public function testDefaultHeadersMapResolvesProperHeader($name, $class)
{
$this->assertEquals($class, $this->headerLoader->get($name));
}
}
Loading