Completed
Pull Request — master (#64)
by Frederik
03:38 queued 01:09
created

FileAttachment::getHeaders()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Mime;
5
6
use Genkgo\Mail\Header\ContentDisposition;
7
use Genkgo\Mail\Header\ContentTransferEncoding;
8
use Genkgo\Mail\Header\ContentType;
9
use Genkgo\Mail\Header\HeaderValue;
10
use Genkgo\Mail\HeaderInterface;
11
use Genkgo\Mail\Stream\Base64EncodedStream;
12
use Genkgo\Mail\StreamInterface;
13
14
final class FileAttachment implements PartInterface
15
{
16
    /**
17
     * @var PartInterface
18
     */
19
    private $decoratedPart;
20
21
    /**
22
     * @param string $filename
23
     * @param ContentType $contentType
24
     * @param string $attachmentName
25
     */
26 15
    public function __construct(string $filename, ContentType $contentType, string $attachmentName = '')
27
    {
28 15
        if (!\file_exists($filename) || !\is_file($filename)) {
29 2
            throw new \InvalidArgumentException('Attachment does not exists');
30
        }
31
32 13
        if ($attachmentName === '') {
33 13
            $attachmentName = \basename($filename);
34
        }
35
36 13
        $resource = \fopen($filename, 'r');
37 13
        if ($resource === false) {
38
            throw new \UnexpectedValueException('Cannot open file ' . $filename . ' for reading');
39
        }
40
41 13
        $this->decoratedPart = (new GenericPart())
42 13
            ->withBody(new Base64EncodedStream($resource))
43 13
            ->withHeader($contentType)
44 13
            ->withHeader(new ContentTransferEncoding('base64'))
45 13
            ->withHeader(ContentDisposition::newAttachment($attachmentName));
46 13
    }
47
48
    /**
49
     * @param string $filename
50
     * @param string $attachmentName
51
     * @return FileAttachment
52
     */
53 1
    public static function fromUnknownFileType(string $filename, string $attachmentName = ''): FileAttachment
54
    {
55 1
        $fileInfo = new \finfo(FILEINFO_MIME);
56 1
        $mime = $fileInfo->file($filename);
57 1
        if ($mime === false) {
58
            return new self(
59
                $filename,
60
                new ContentType('application/octet-stream'),
61
                $attachmentName
62
            );
63
        }
64
65 1
        $headerValue = HeaderValue::fromString($mime);
66
67
        try {
68 1
            $charset = $headerValue->getParameter('charset')->getValue();
69 1
            if ($charset === 'binary') {
70
                $contentType = new ContentType($headerValue->getRaw());
71
            } else {
72 1
                $contentType = new ContentType($headerValue->getRaw(), $charset);
73
            }
74
        } catch (\UnexpectedValueException $e) {
75
            $contentType = new ContentType($headerValue->getRaw());
76
        }
77
78 1
        return new self(
79 1
            $filename,
80
            $contentType,
81
            $attachmentName
82
        );
83
    }
84
85
    /**
86
     * @return iterable<HeaderInterface>
0 ignored issues
show
Documentation introduced by
The doc-type iterable<HeaderInterface> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
87
     */
88 2
    public function getHeaders(): iterable
89
    {
90 2
        return $this->decoratedPart->getHeaders();
91
    }
92
93
    /**
94
     * @param string $name
95
     * @return bool
96
     */
97 2
    public function hasHeader(string $name): bool
98
    {
99 2
        return $this->decoratedPart->hasHeader($name);
100
    }
101
102
    /**
103
     * @param string $name
104
     * @return HeaderInterface
105
     */
106 3
    public function getHeader(string $name): HeaderInterface
107
    {
108 3
        return $this->decoratedPart->getHeader($name);
109
    }
110
111
    /**
112
     * @param HeaderInterface $header
113
     * @return PartInterface
114
     */
115 4
    public function withHeader(HeaderInterface $header): PartInterface
116
    {
117 4
        if (\strtolower((string)$header->getName()) === 'content-disposition') {
118 2
            throw new \InvalidArgumentException('Cannot modify content disposition for file attachment');
119
        }
120
121 2
        $clone = clone $this;
122 2
        $clone->decoratedPart = $this->decoratedPart->withHeader($header);
123 2
        return $clone;
124
    }
125
126
    /**
127
     * @param string $name
128
     * @return PartInterface
129
     */
130 4
    public function withoutHeader(string $name): PartInterface
131
    {
132 4
        if (\strtolower($name) === 'content-disposition') {
133 2
            throw new \InvalidArgumentException('Cannot modify content disposition for file attachment');
134
        }
135
136 2
        $clone = clone $this;
137 2
        $clone->decoratedPart = $this->decoratedPart->withoutHeader($name);
138 2
        return $clone;
139
    }
140
141
    /**
142
     * @param StreamInterface $body
143
     * @return PartInterface
144
     */
145 2
    public function withBody(StreamInterface $body): PartInterface
146
    {
147 2
        throw new \RuntimeException('Cannot modify body of FileAttachment');
148
    }
149
150
    /**
151
     * @return StreamInterface
152
     */
153 2
    public function getBody(): StreamInterface
154
    {
155 2
        return $this->decoratedPart->getBody();
156
    }
157
}
158