Skip to content
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

Fixes #39 Fixes #40 remove laminas-loader dependency #95

Merged
merged 14 commits into from
Jul 30, 2020
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