Passed
Push — 2.0 ( df1b1e...20b3e4 )
by Zaahid
08:44 queued 05:27
created

MailMimeParser   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Test Coverage

Coverage 90.91%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 8
eloc 20
c 4
b 0
f 0
dl 0
loc 112
ccs 20
cts 22
cp 0.9091
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setDependencyContainer() 0 3 1
A __construct() 0 7 2
A getDependencyContainer() 0 3 1
A parse() 0 10 2
A configureDependencyContainer() 0 6 2
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
8
namespace ZBateson\MailMimeParser;
9
10
use GuzzleHttp\Psr7\CachingStream;
11
use GuzzleHttp\Psr7\Utils;
12
use Psr\Http\Message\StreamInterface;
13
use ZBateson\MailMimeParser\Parser\MessageParser;
14
15
/**
16
 * Parses a MIME message into an {@see IMessage} object.
17
 *
18
 * The class sets up the Pimple dependency injection container with the ability
19
 * to override and/or provide specialized provider
20
 * {@see https://pimple.symfony.com/ \Pimple\ServiceProviderInterface}
21
 * classes to extend default classes used by MailMimeParser.
22
 *
23
 * To invoke, call parse on a MailMimeParser object.
24
 *
25
 * ```php
26
 * $parser = new MailMimeParser();
27
 * // the resource is attached due to the second parameter being true and will
28
 * // be closed when the returned IMessage is destroyed
29
 * $message = $parser->parse(fopen('path/to/file.txt'), true);
30
 * // use $message here
31
 * ```
32
 *
33
 * @author Zaahid Bateson
34
 */
35
class MailMimeParser
36
{
37
    /**
38
     * @var string the default charset used to encode strings (or string content
39
     *      like streams) returned by MailMimeParser (for e.g. the string
40
     *      returned by calling $message->getTextContent()).
41
     */
42
    public const DEFAULT_CHARSET = 'UTF-8';
43
44
    /**
45
     * @var Container dependency injection container
46
     */
47
    protected static $di = null;
48
49
    /**
50
     * @var MessageParser for parsing messages
51
     */
52
    protected $messageParser;
53
54
    /**
55
     * Returns the container.
56
     *
57
     * @return Container
58
     */
59 106
    public static function getDependencyContainer()
60
    {
61 106
        return static::$di;
62
    }
63
64
    /**
65
     * (Re)creates the container using the passed providers.
66
     *
67
     * This is necessary if configuration needs to be reset to parse emails
68
     * differently.
69
     *
70
     * Note that reconfiguring the dependency container can have an affect on
71
     * existing objects -- for instance if a provider were to override a
72
     * factory class, and an operation on an existing instance were to try to
73
     * create an object using that factory class, the new factory class would be
74
     * returned.  In other words, references to the Container are not maintained
75
     * in a non-static context separately, so care should be taken when
76
     * reconfiguring the parser.
77
     *
78
     * @param \Pimple\ServiceProviderInterface[] $providers
79
     */
80 1
    public static function configureDependencyContainer(array $providers = [])
81
    {
82 1
        static::$di = new Container();
83 1
        $di = static::$di;
84 1
        foreach ($providers as $provider) {
85
            $di->register($provider);
86
        }
87
    }
88
89
    /**
90
     * Override the dependency container completely.  If multiple configurations
91
     * are known to be needed, it would be better to keep the different
92
     * Container configurations and call setDependencyContainer instead of
93
     * {@see MailMimeParser::configureDependencyContainer}, which instantiates a
94
     * new {@see Container} on every call.
95
     *
96
     * @param Container $di
97
     */
98 4
    public static function setDependencyContainer(?Container $di = null)
99
    {
100 4
        static::$di = $di;
101
    }
102
103
    /**
104
     * Initializes the dependency container if not already initialized.
105
     *
106
     * To configure custom {@see https://pimple.symfony.com/ \Pimple\ServiceProviderInterface}
107
     * objects, call {@see MailMimeParser::configureDependencyContainer()}
108
     * before creating a MailMimeParser instance.
109
     */
110 109
    public function __construct()
111
    {
112 109
        if (static::$di === null) {
113 1
            static::configureDependencyContainer();
114
        }
115 109
        $di = static::$di;
116 109
        $this->messageParser = $di[\ZBateson\MailMimeParser\Parser\MessageParser::class];
117
    }
118
119
    /**
120
     * Parses the passed stream handle or string into an {@see IMessage} object
121
     * and returns it.
122
     *
123
     * If the passed $resource is a resource handle or StreamInterface, the
124
     * resource must remain open while the returned IMessage object exists.
125
     * Pass true as the second argument to have the resource attached to the
126
     * IMessage and closed for you when it's destroyed, or pass false to
127
     * manually close it if it should remain open after the IMessage object is
128
     * destroyed.
129
     *
130
     * @param resource|StreamInterface|string $resource The resource handle to
131
     *        the input stream of the mime message, or a string containing a
132
     *        mime message.
133
     * @param bool $attached pass true to have it attached to the returned
134
     *        IMessage and destroyed with it.
135
     * @return \ZBateson\MailMimeParser\IMessage
136
     */
137 108
    public function parse($resource, $attached)
138
    {
139 108
        $stream = Utils::streamFor(
140 108
            $resource,
141 108
            ['metadata' => ['mmp-detached-stream' => ($attached !== true)]]
142 108
        );
143 108
        if (!$stream->isSeekable()) {
144
            $stream = new CachingStream($stream);
145
        }
146 108
        return $this->messageParser->parse($stream);
147
    }
148
}
149