Test Failed
Push — 1.0.0 ( dd1332...30b11b )
by Zaahid
02:32
created

ParentPart::getAllPartsByMimeType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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\Part;
8
9
use Psr\Http\Message\StreamInterface;
10
use ZBateson\MailMimeParser\Message\PartFilterFactory;
11
use ZBateson\MailMimeParser\Message\PartFilter;
12
use ZBateson\MailMimeParser\Stream\StreamFactory;
13
14
/**
15
 * A MessagePart that contains children.
16
 *
17
 * @author Zaahid Bateson
18
 */
19
abstract class ParentPart extends MessagePart
20
{
21
    /**
22
     * @var PartFilterFactory factory object responsible for create PartFilters
23
     */
24
    protected $partFilterFactory;
25
26
    /**
27
     * @var MessagePart[] array of child parts
28
     */
29
    protected $children = [];
30
31
    /**
32
     * @param PartStreamFilterManager $partStreamFilterManager
33
     * @param StreamFactory $streamFactory
34
     * @param PartFilterFactory $partFilterFactory
35
     * @param PartBuilder $partBuilder
36
     * @param StreamInterface $stream
37
     * @param StreamInterface $contentStream
38
     */
39
    public function __construct(
40
        PartStreamFilterManager $partStreamFilterManager,
41
        StreamFactory $streamFactory,
42
        PartFilterFactory $partFilterFactory,
43
        PartBuilder $partBuilder,
44
        StreamInterface $stream,
45
        StreamInterface $contentStream = null
46
    ) {
47
        parent::__construct($partStreamFilterManager, $streamFactory, $stream, $contentStream);
48
        $this->partFilterFactory = $partFilterFactory;
49
50
        $pbChildren = $partBuilder->getChildren();
51
        if (!empty($pbChildren)) {
52
            $this->children = array_map(function ($child) use ($stream) {
53
                $childPart = $child->createMessagePart($stream);
54
                $childPart->parent = $this;
55
                return $childPart;
56
            }, $pbChildren);
57
        }
58
    }
59
60
    /**
61
     * Returns all parts, including the current object, and all children below
62
     * it (including children of children, etc...)
63
     *
64
     * @return MessagePart[]
65
     */
66
    protected function getAllNonFilteredParts()
67
    {
68
        $parts = [ $this ];
69
        foreach ($this->children as $part) {
70
            if ($part instanceof MimePart) {
71
                $parts = array_merge(
72
                    $parts,
73
                    $part->getAllNonFilteredParts()
74
                );
75
            } else {
76
                array_push($parts, $part);
77
            }
78
        }
79
        return $parts;
80
    }
81
82
    /**
83
     * Returns the part at the given 0-based index, or null if none is set.
84
     *
85
     * Note that the first part returned is the current part itself.  This is
86
     * often desirable for queries with a PartFilter, e.g. looking for a
87
     * MessagePart with a specific Content-Type that may be satisfied by the
88
     * current part.
89
     *
90
     * @param int $index
91
     * @param PartFilter $filter
92
     * @return MessagePart
93
     */
94
    public function getPart($index, PartFilter $filter = null)
95
    {
96
        $parts = $this->getAllParts($filter);
97
        if (!isset($parts[$index])) {
98
            return null;
99
        }
100
        return $parts[$index];
101
    }
102
103
    /**
104
     * Returns the current part, all child parts, and child parts of all
105
     * children optionally filtering them with the provided PartFilter.
106
     *
107
     * The first part returned is always the current MimePart.  This is often
108
     * desirable as it may be a valid MimePart for the provided PartFilter.
109
     *
110
     * @param PartFilter $filter an optional filter
111
     * @return MessagePart[]
112
     */
113
    public function getAllParts(PartFilter $filter = null)
114
    {
115
        $parts = $this->getAllNonFilteredParts();
116
        if (!empty($filter)) {
117
            return array_values(array_filter(
118
                $parts,
119
                [ $filter, 'filter' ]
120
            ));
121
        }
122
        return $parts;
123
    }
124
125
    /**
126
     * Returns the total number of parts in this and all children.
127
     *
128
     * Note that the current part is considered, so the minimum getPartCount is
129
     * 1 without a filter.
130
     *
131
     * @param PartFilter $filter
132
     * @return int
133
     */
134
    public function getPartCount(PartFilter $filter = null)
135
    {
136
        return count($this->getAllParts($filter));
137
    }
138
139
    /**
140
     * Returns the direct child at the given 0-based index, or null if none is
141
     * set.
142
     *
143
     * @param int $index
144
     * @param PartFilter $filter
145
     * @return MessagePart
146
     */
147
    public function getChild($index, PartFilter $filter = null)
148
    {
149
        $parts = $this->getChildParts($filter);
150
        if (!isset($parts[$index])) {
151
            return null;
152
        }
153
        return $parts[$index];
154
    }
155
156
    /**
157
     * Returns all direct child parts.
158
     *
159
     * If a PartFilter is provided, the PartFilter is applied before returning.
160
     *
161
     * @param PartFilter $filter
162
     * @return MessagePart[]
163
     */
164
    public function getChildParts(PartFilter $filter = null)
165
    {
166
        if ($filter !== null) {
167
            return array_values(array_filter($this->children, [ $filter, 'filter' ]));
168
        }
169
        return $this->children;
170
    }
171
172
    /**
173
     * Returns the number of direct children under this part.
174
     *
175
     * @param PartFilter $filter
176
     * @return int
177
     */
178
    public function getChildCount(PartFilter $filter = null)
179
    {
180
        return count($this->getChildParts($filter));
181
    }
182
183
    /**
184
     * Returns the part associated with the passed mime type if it exists.
185
     *
186
     * @param string $mimeType
187
     * @return MessagePart or null
188
     */
189
    public function getPartByMimeType($mimeType, $index = 0)
190
    {
191
        $partFilter = $this->partFilterFactory->newFilterFromContentType($mimeType);
192
        return $this->getPart($index, $partFilter);
193
    }
194
195
    /**
196
     * Returns an array of all parts associated with the passed mime type if any
197
     * exist or null otherwise.
198
     *
199
     * @param string $mimeType
200
     * @return MessagePart[] or null
201
     */
202
    public function getAllPartsByMimeType($mimeType)
203
    {
204
        $partFilter = $this->partFilterFactory->newFilterFromContentType($mimeType);
205
        return $this->getAllParts($partFilter);
206
    }
207
208
    /**
209
     * Returns the number of parts matching the passed $mimeType
210
     *
211
     * @param string $mimeType
212
     * @return int
213
     */
214
    public function getCountOfPartsByMimeType($mimeType)
215
    {
216
        $partFilter = $this->partFilterFactory->newFilterFromContentType($mimeType);
217
        return $this->getPartCount($partFilter);
218
    }
219
220
    /**
221
     * Registers the passed part as a child of the current part.
222
     *
223
     * If the $position parameter is non-null, adds the part at the passed
224
     * position index.
225
     *
226
     * @param MessagePart $part
227
     * @param int $position
228
     */
229
    public function addChild(MessagePart $part, $position = null)
230
    {
231
        if ($part !== $this) {
0 ignored issues
show
introduced by
The condition $part !== $this is always true.
Loading history...
232
            $part->parent = $this;
233
            array_splice(
234
                $this->children,
235
                ($position === null) ? count($this->children) : $position,
236
                0,
237
                [ $part ]
238
            );
239
            $this->onChange();
240
        }
241
    }
242
243
    /**
244
     * Removes the child part from this part and returns its position or
245
     * null if it wasn't found.
246
     *
247
     * Note that if the part is not a direct child of this part, the returned
248
     * position is its index within its parent (calls removePart on its direct
249
     * parent).
250
     *
251
     * @param MessagePart $part
252
     * @return int or null if not found
253
     */
254
    public function removePart(MessagePart $part)
255
    {
256
        $parent = $part->getParent();
257
        if ($this !== $parent && $parent !== null) {
258
            return $parent->removePart($part);
259
        } else {
260
            $position = array_search($part, $this->children, true);
261
            if ($position !== false) {
262
                array_splice($this->children, $position, 1);
0 ignored issues
show
Bug introduced by
It seems like $position can also be of type string; however, parameter $offset of array_splice() does only seem to accept integer, 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

262
                array_splice($this->children, /** @scrutinizer ignore-type */ $position, 1);
Loading history...
263
                $this->onChange();
264
                return $position;
265
            }
266
        }
267
        return null;
268
    }
269
270
    /**
271
     * Removes all parts that are matched by the passed PartFilter.
272
     *
273
     * @param \ZBateson\MailMimeParser\Message\PartFilter $filter
274
     */
275
    public function removeAllParts(PartFilter $filter = null)
276
    {
277
        foreach ($this->getAllParts($filter) as $part) {
278
            $this->removePart($part);
279
        }
280
    }
281
}
282