Test Failed
Pull Request — master (#171)
by Zaahid
04:55
created

MultiPart::addChild()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 6
rs 10
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
namespace ZBateson\MailMimeParser\Message;
8
9
use ZBateson\MailMimeParser\MailMimeParser;
10
use ZBateson\MailMimeParser\Message\PartStreamContainer;
11
use ZBateson\MailMimeParser\Message\PartFilter;
12
use Iterator;
13
use AppendIterator;
14
use ArrayIterator;
15
use RecursiveIteratorIterator;
16
17
/**
18
 * A MultiPart mime part.
19
 *
20
 * @author Zaahid Bateson
21
 */
22
abstract class MultiPart extends MessagePart implements IMultiPart
23
{
24
    /**
25
     * @var PartChildrenContainer child part container
26
     */
27
    protected $partChildrenContainer;
28
29
    public function __construct(
30
        IMimePart $parent = null,
31
        PartStreamContainer $streamContainer = null,
32
        PartChildrenContainer $partChildrenContainer = null
33
    ) {
34
        parent::__construct($streamContainer, $parent);
0 ignored issues
show
Bug introduced by
It seems like $streamContainer can also be of type null; however, parameter $streamContainer of ZBateson\MailMimeParser\...sagePart::__construct() does only seem to accept ZBateson\MailMimeParser\...age\PartStreamContainer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

34
        parent::__construct(/** @scrutinizer ignore-type */ $streamContainer, $parent);
Loading history...
35
        if ($partChildrenContainer === null) {
36
            $di = MailMimeParser::getDependencyContainer();
37
            $partChildrenContainer = $di['\ZBateson\MailMimeParser\Message\PartChildrenContainer'];
38
        }
39
        $this->partChildrenContainer = $partChildrenContainer;
40
    }
41
42
    public function isMultiPart()
43
    {
44
        // casting to bool, preg_match returns 1 for true
45
        return (bool) (preg_match(
46
            '~multipart/.*~i',
47
            $this->getContentType()
48
        ));
49
    }
50
51
    private function getAllPartsIterator()
52
    {
53
        $iter = new AppendIterator();
54
        $iter->append(new ArrayIterator([ $this ]));
55
        $iter->append(new RecursiveIteratorIterator($this->partChildrenContainer, RecursiveIteratorIterator::SELF_FIRST));
56
        return $iter;
57
    }
58
59
    private function iteratorFindAt(Iterator $iter, $index, $fnFilter = null)
60
    {
61
        $pos = 0;
62
        foreach ($iter as $part) {
63
            if (($fnFilter === null || $fnFilter($part))) {
64
                if ($index === $pos) {
65
                    return $part;
66
                }
67
                ++$pos;
68
            }
69
        }
70
    }
71
72
    public function getPart($index, $fnFilter = null)
73
    {
74
        return $this->iteratorFindAt(
75
            $this->getAllPartsIterator(),
76
            $index,
77
            $fnFilter
78
        );
79
    }
80
81
    public function getAllParts($fnFilter = null)
82
    {
83
        $array = iterator_to_array($this->getAllPartsIterator(), false);
84
        if ($fnFilter !== null) {
85
            return array_values(array_filter($array, $fnFilter));
86
        }
87
        return $array;
88
    }
89
90
    public function getPartCount($fnFilter = null)
91
    {
92
        return count($this->getAllParts($fnFilter));
93
    }
94
95
    public function getChild($index, $fnFilter = null)
96
    {
97
        return $this->iteratorFindAt(
98
            $this->partChildrenContainer,
99
            $index,
100
            $fnFilter
101
        );
102
    }
103
104
    public function getChildIterator()
105
    {
106
        return $this->partChildrenContainer;
107
    }
108
109
    public function getChildParts($fnFilter = null)
110
    {
111
        $array = iterator_to_array($this->partChildrenContainer, false);
112
        if ($fnFilter !== null) {
113
            return array_values(array_filter($array, $fnFilter));
114
        }
115
        return $array;
116
    }
117
118
    public function getChildCount($fnFilter = null)
119
    {
120
        return count($this->getChildParts($fnFilter));
121
    }
122
123
    public function getPartByMimeType($mimeType, $index = 0)
124
    {
125
        return $this->getPart($index, PartFilter::fromContentType($mimeType));
126
    }
127
128
    public function getAllPartsByMimeType($mimeType)
129
    {
130
        return $this->getAllParts(PartFilter::fromContentType($mimeType));
131
    }
132
133
    public function getCountOfPartsByMimeType($mimeType)
134
    {
135
        return $this->getPartCount(PartFilter::fromContentType($mimeType));
136
    }
137
138
    public function getPartByContentId($contentId)
139
    {
140
        $sanitized = preg_replace('/^\s*<|>\s*$/', '', $contentId);
141
        return $this->getPart(0, function (IMessagePart $part) use ($sanitized) {
142
            return strcasecmp($part->getContentId(), $sanitized) === 0;
0 ignored issues
show
Bug introduced by
It seems like $part->getContentId() can also be of type null; however, parameter $string1 of strcasecmp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

142
            return strcasecmp(/** @scrutinizer ignore-type */ $part->getContentId(), $sanitized) === 0;
Loading history...
143
        });
144
    }
145
146
    public function addChild(IMessagePart $part, $position = null)
147
    {
148
        if ($part !== $this) {
0 ignored issues
show
introduced by
The condition $part !== $this is always true.
Loading history...
149
            $part->parent = $this;
0 ignored issues
show
Bug introduced by
Accessing parent on the interface ZBateson\MailMimeParser\Message\IMessagePart suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
150
            $this->partChildrenContainer->add($part, $position);
151
            $this->notify();
152
        }
153
    }
154
155
    public function removePart(IMessagePart $part)
156
    {
157
        $parent = $part->getParent();
158
        if ($this !== $parent && $parent !== null) {
159
            return $parent->removePart($part);
160
        } else {
161
            $position = $this->partChildrenContainer->remove($part);
162
            if ($position !== null) {
163
                $this->notify();
164
            }
165
            return $position;
166
        }
167
    }
168
169
    public function removeAllParts($fnFilter = null)
170
    {
171
        foreach ($this->getAllParts($fnFilter) as $part) {
172
            if ($part === $this) {
173
                continue;
174
            }
175
            $this->removePart($part);
176
        }
177
    }
178
}
179