Completed
Push — master ( 7edc90...d4566f )
by Zaahid
02:46
created

GenericConsumer::checkAddFilteredSpace()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
rs 8.8571
cc 5
eloc 10
nc 3
nop 4
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\Header\Consumer;
8
9
use ZBateson\MailMimeParser\Header\Part\Token;
10
11
/**
12
 * A minimal implementation of AbstractConsumer defining a CommentConsumer and
13
 * QuotedStringConsumer as sub-consumers, and splitting tokens by whitespace.
14
 *
15
 * @author Zaahid Bateson
16
 */
17
class GenericConsumer extends AbstractConsumer
18
{
19
    /**
20
     * Returns \ZBateson\MailMimeParser\Header\Consumer\CommentConsumer and
21
     * \ZBateson\MailMimeParser\Header\Consumer\QuotedStringConsumer as
22
     * sub-consumers.
23
     * 
24
     * @return AbstractConsumer[] the sub-consumers
25
     */
26
    protected function getSubConsumers()
27
    {
28
        return [
29
            $this->consumerService->getCommentConsumer(),
30
            $this->consumerService->getQuotedStringConsumer(),
31
        ];
32
    }
33
    
34
    /**
35
     * Returns the regex '\s+' (whitespace) pattern matcher as a token marker so
36
     * the header value is split along whitespace characters.  GenericConsumer
37
     * filters out whitespace-only tokens from getPartForToken.
38
     * 
39
     * The whitespace character delimits mime-encoded parts for decoding.
40
     * 
41
     * @return string[] an array of regex pattern matchers
42
     */
43
    protected function getTokenSeparators()
44
    {
45
        return ['\s+'];
46
    }
47
    
48
    /**
49
     * GenericConsumer doesn't have start/end tokens, and so always returns
50
     * false.
51
     * 
52
     * @param string $token
53
     * @return boolean false
54
     */
55
    protected function isEndToken($token)
56
    {
57
        return false;
58
    }
59
    
60
    /**
61
     * GenericConsumer doesn't have start/end tokens, and so always returns
62
     * false.
63
     * 
64
     * @param string $token
65
     * @return boolean false
66
     */
67
    protected function isStartToken($token)
68
    {
69
        return false;
70
    }
71
    
72
    /**
73
     * Creates and returns a
74
     * \ZBateson\MailMimeParser\Header\Part\MimeLiteralPart out of the passed
75
     * string token and returns it.
76
     * 
77
     * @param string $token
78
     * @param bool $isLiteral
79
     * @return \ZBateson\MailMimeParser\Header\Part\HeaderPart
80
     */
81 View Code Duplication
    protected function getPartForToken($token, $isLiteral)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82
    {
83
        if (preg_match('/^\s+$/', $token) && !$isLiteral) {
84
            return $this->partFactory->newToken(' ');
85
        } elseif ($isLiteral) {
86
            return $this->partFactory->newLiteralPart($token);
87
        } else {
88
            return $this->partFactory->newMimeLiteralPart($token);
89
        }
90
    }
91
    
92
    /**
93
     * Checks if the passed space part should be added to the returned parts and
94
     * adds it.
95
     * 
96
     * Never adds a space if it's the first part, otherwise only add it if
97
     * either part isn't set to ignore the space
98
     * 
99
     * @param array $parts
100
     * @param array $retParts
101
     * @param ZBateson\MailMimeParser\Header\Part\HeaderPart $spacePart
102
     * @param int $curIndex
103
     * @return boolean true if the part was added
104
     */
105
    private function checkAddFilteredSpace(array $parts, array &$retParts, &$spacePart, $curIndex)
106
    {
107
        $lastPart = end($retParts);
108
        $count = count($parts);
109
        for ($j = $curIndex; $j < $count; ++$j) {
110
            $next = $parts[$j];
111
            if ($lastPart !== null && (!$lastPart->ignoreSpacesAfter() || !$next->ignoreSpacesBefore())) {
112
                $retParts[] = $spacePart;
113
                $spacePart = null;
114
                return true;
115
            }
116
        }
117
        return false;
118
    }
119
    
120
    /**
121
     * Filters out ignorable spaces between parts in the passed array.
122
     * 
123
     * Spaces with parts on either side of it that specify they can be ignored
124
     * are filtered out.  filterIgnoredSpaces is called from within
125
     * processParts, and if needed by an implementing class that overrides
126
     * processParts, must be specifically called.
127
     * 
128
     * @param ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
129
     * @return ZBateson\MailMimeParser\Header\Part\HeaderPart[]
130
     */
131
    protected function filterIgnoredSpaces(array $parts)
132
    {
133
        $retParts = [];
134
        $spacePart = null;
135
        $count = count($parts);
136
        for ($i = 0; $i < $count; ++$i) {
137
            $part = $parts[$i];
138
            if ($part instanceof Token && $part->isSpace()) {
139
                $spacePart = $part;
140
                continue;
141
            } elseif ($spacePart !== null && $part->getValue() !== '') {
142
                $this->checkAddFilteredSpace($parts, $retParts, $spacePart, $i);
143
            }
144
            $retParts[] = $part;
145
        }
146
        // ignore trailing spaces
147
        return $retParts;
148
    }
149
    
150
    /**
151
     * Overridden to combine all part values into a single string and return it
152
     * as an array with a single element.
153
     * 
154
     * @param ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
155
     * @return ZBateson\MailMimeParser\Header\Part\LiteralPart[]
156
     */
157
    protected function processParts(array $parts)
158
    {
159
        $strValue = '';
160
        $filtered = $this->filterIgnoredSpaces($parts);
161
        foreach ($filtered as $part) {
162
            $strValue .= $part->getValue();
163
        }
164
        return [$this->partFactory->newLiteralPart($strValue)];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array($this->part...iteralPart($strValue)); (ZBateson\MailMimeParser\Header\Part\LiteralPart[]) is incompatible with the return type of the parent method ZBateson\MailMimeParser\...tConsumer::processParts of type ZBateson\MailMimeParser\...eader\Part\HeaderPart[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
165
    }
166
}
167