Completed
Push — master ( d4566f...31a5e9 )
by Zaahid
02:27
created

GenericConsumer::isStartToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 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
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
 * Note that GenericConsumer should be instantiated with a
16
 * MimeLiteralPartFactory instead of a HeaderPartFactory.  Sub-classes may not
17
 * need MimeLiteralPartFactory instances though.
18
 * 
19
 * @author Zaahid Bateson
20
 */
21
class GenericConsumer extends AbstractConsumer
22
{
23
    /**
24
     * Returns \ZBateson\MailMimeParser\Header\Consumer\CommentConsumer and
25
     * \ZBateson\MailMimeParser\Header\Consumer\QuotedStringConsumer as
26
     * sub-consumers.
27
     * 
28
     * @return AbstractConsumer[] the sub-consumers
29
     */
30
    protected function getSubConsumers()
31
    {
32
        return [
33
            $this->consumerService->getCommentConsumer(),
34
            $this->consumerService->getQuotedStringConsumer(),
35
        ];
36
    }
37
    
38
    /**
39
     * Returns the regex '\s+' (whitespace) pattern matcher as a token marker so
40
     * the header value is split along whitespace characters.  GenericConsumer
41
     * filters out whitespace-only tokens from getPartForToken.
42
     * 
43
     * The whitespace character delimits mime-encoded parts for decoding.
44
     * 
45
     * @return string[] an array of regex pattern matchers
46
     */
47
    protected function getTokenSeparators()
48
    {
49
        return ['\s+'];
50
    }
51
    
52
    /**
53
     * GenericConsumer doesn't have start/end tokens, and so always returns
54
     * false.
55
     * 
56
     * @param string $token
57
     * @return boolean false
58
     */
59
    protected function isEndToken($token)
60
    {
61
        return false;
62
    }
63
    
64
    /**
65
     * GenericConsumer doesn't have start/end tokens, and so always returns
66
     * false.
67
     * 
68
     * @param string $token
69
     * @return boolean false
70
     */
71
    protected function isStartToken($token)
72
    {
73
        return false;
74
    }
75
    
76
    /**
77
     * Checks if the passed space part should be added to the returned parts and
78
     * adds it.
79
     * 
80
     * Never adds a space if it's the first part, otherwise only add it if
81
     * either part isn't set to ignore the space
82
     * 
83
     * @param array $parts
84
     * @param array $retParts
85
     * @param ZBateson\MailMimeParser\Header\Part\HeaderPart $spacePart
86
     * @param int $curIndex
87
     * @return boolean true if the part was added
88
     */
89
    private function checkAddFilteredSpace(array $parts, array &$retParts, &$spacePart, $curIndex)
90
    {
91
        $lastPart = end($retParts);
92
        $count = count($parts);
93
        for ($j = $curIndex; $j < $count; ++$j) {
94
            $next = $parts[$j];
95
            if ($lastPart !== null && (!$lastPart->ignoreSpacesAfter() || !$next->ignoreSpacesBefore())) {
96
                $retParts[] = $spacePart;
97
                $spacePart = null;
98
                return true;
99
            }
100
        }
101
        return false;
102
    }
103
    
104
    /**
105
     * Filters out ignorable spaces between parts in the passed array.
106
     * 
107
     * Spaces with parts on either side of it that specify they can be ignored
108
     * are filtered out.  filterIgnoredSpaces is called from within
109
     * processParts, and if needed by an implementing class that overrides
110
     * processParts, must be specifically called.
111
     * 
112
     * @param ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
113
     * @return ZBateson\MailMimeParser\Header\Part\HeaderPart[]
114
     */
115
    protected function filterIgnoredSpaces(array $parts)
116
    {
117
        $retParts = [];
118
        $spacePart = null;
119
        $count = count($parts);
120
        for ($i = 0; $i < $count; ++$i) {
121
            $part = $parts[$i];
122
            if ($part instanceof Token && $part->isSpace()) {
123
                $spacePart = $part;
124
                continue;
125
            } elseif ($spacePart !== null && $part->getValue() !== '') {
126
                $this->checkAddFilteredSpace($parts, $retParts, $spacePart, $i);
127
            }
128
            $retParts[] = $part;
129
        }
130
        // ignore trailing spaces
131
        return $retParts;
132
    }
133
    
134
    /**
135
     * Overridden to combine all part values into a single string and return it
136
     * as an array with a single element.
137
     * 
138
     * @param ZBateson\MailMimeParser\Header\Part\HeaderPart[] $parts
139
     * @return ZBateson\MailMimeParser\Header\Part\LiteralPart[]
140
     */
141
    protected function processParts(array $parts)
142
    {
143
        $strValue = '';
144
        $filtered = $this->filterIgnoredSpaces($parts);
145
        foreach ($filtered as $part) {
146
            $strValue .= $part->getValue();
147
        }
148
        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...
149
    }
150
}
151