Passed
Push — master ( 46ed75...ca2387 )
by Zaahid
03:33
created

CommentConsumerService::advanceToNextToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
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\Header\Consumer;
9
10
use ZBateson\MailMimeParser\Header\Part\MimeLiteralPartFactory;
11
use ZBateson\MailMimeParser\Header\IHeaderPart;
12
use ZBateson\MailMimeParser\Header\Part\CommentPart;
13
use ZBateson\MailMimeParser\Header\Part\LiteralPart;
14
use Iterator;
15
16
/**
17
 * Consumes all tokens within parentheses as comments.
18
 *
19
 * Parenthetical comments in mime-headers can be nested within one another.  The
20
 * outer-level continues after an inner-comment ends.  Additionally,
21
 * quoted-literals may exist with comments as well meaning a parenthesis inside
22
 * a quoted string would not begin or end a comment section.
23
 *
24
 * In order to satisfy these specifications, CommentConsumerService inherits
25
 * from GenericConsumerService which defines CommentConsumerService and
26
 * QuotedStringConsumerService as sub-consumers.
27
 *
28
 * Examples:
29
 * X-Mime-Header: Some value (comment)
30
 * X-Mime-Header: Some value (comment (nested comment) still in comment)
31
 * X-Mime-Header: Some value (comment "and part of original ) comment" -
32
 *      still a comment)
33
 *
34
 * @author Zaahid Bateson
35
 */
36
class CommentConsumerService extends GenericConsumerService
37
{
38 4
    public function __construct(
39
        MimeLiteralPartFactory $partFactory,
40
        QuotedStringConsumerService $quotedStringConsumerService
41
    ) {
42 4
        parent::__construct(
43 4
            $partFactory,
44 4
            $this,
45 4
            $quotedStringConsumerService
46 4
        );
47
    }
48
49
    /**
50
     * Returns patterns matching open and close parenthesis characters
51
     * as separators.
52
     *
53
     * @return string[] the patterns
54
     */
55 6
    protected function getTokenSeparators() : array
56
    {
57 6
        return ['\(', '\)'];
58
    }
59
60
    /**
61
     * Returns true if the token is an open parenthesis character, '('.
62
     */
63 109
    protected function isStartToken(string $token) : bool
64
    {
65 109
        return ($token === '(');
66
    }
67
68
    /**
69
     * Returns true if the token is a close parenthesis character, ')'.
70
     */
71 19
    protected function isEndToken(string $token) : bool
72
    {
73 19
        return ($token === ')');
74
    }
75
76
    /**
77
     * Instantiates and returns Part\Token objects.
78
     *
79
     * Tokens from this and sub-consumers are combined into a Part\CommentPart
80
     * in processParts.
81
     */
82 19
    protected function getPartForToken(string $token, bool $isLiteral) : ?IHeaderPart
83
    {
84 19
        return $this->partFactory->newToken($token);
85
    }
86
87
    /**
88
     * Calls $tokens->next() and returns.
89
     *
90
     * The default implementation checks if the current token is an end token,
91
     * and will not advance past it.  Because a comment part of a header can be
92
     * nested, its implementation must advance past its own 'end' token.
93
     *
94
     * @return static
95
     */
96 19
    protected function advanceToNextToken(Iterator $tokens, bool $isStartToken) : AbstractConsumerService
97
    {
98 19
        $tokens->next();
99 19
        return $this;
100
    }
101
102
    /**
103
     * Post processing involves creating a single Part\CommentPart out of
104
     * generated parts from tokens.  The Part\CommentPart is returned in an
105
     * array.
106
     *
107
     * @param IHeaderPart[] $parts
108
     * @return IHeaderPart[]
109
     */
110 19
    protected function processParts(array $parts) : array
111
    {
112 19
        $comment = '';
113 19
        foreach ($parts as $part) {
114
            // order is important here - CommentPart extends LiteralPart
115 19
            if ($part instanceof CommentPart) {
116 3
                $comment .= '(' . $part->getComment() . ')';
117 19
            } elseif ($part instanceof LiteralPart) {
118 1
                $comment .= '"' . \str_replace('(["\\])', '\$1', $part->getValue()) . '"';
119
            } else {
120 19
                $comment .= $part->getValue();
121
            }
122
        }
123 19
        return [$this->partFactory->newCommentPart($comment)];
124
    }
125
}
126