Test Failed
Pull Request — master (#29)
by Nicolas
02:57
created

Message::isCompressionAllowed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 0
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Puzzle\AMQP\Messages;
4
5
use Psr\Log\InvalidArgumentException;
6
use Puzzle\AMQP\WritableMessage;
7
use Puzzle\AMQP\Messages\Bodies\NullBody;
8
use Puzzle\Pieces\ConvertibleToString;
9
10
class Message implements WritableMessage, ConvertibleToString
11
{
12
    use BodySetter;
13
    
14
    private
15
        $body,
16
        $canBeDroppedSilently,
17
        $allowCompression,
18
        $headers,
19
        $attributes;
20
21 27
    public function __construct($routingKey = '')
22 1
    {
23 27
        $this->body = new NullBody();
24 27
        
25 27
        $this->canBeDroppedSilently = true;
26 27
        $this->allowCompression = false;
27 27
        
28 27
        $this->headers = array();
29
        $this->initializeAttributes();
30 27
        
31
        $this->changeRoutingKey($routingKey);
32 27
    }
33 27
34
    public function changeRoutingKey($routingKey)
35 27
    {
36
        $this->setAttribute('routing_key', $routingKey);
37 27
    }
38 27
    
39 27
    private function initializeAttributes()
40 27
    {
41
        $this->attributes = array(
42 10
            'routing_key' => null,
43 27
            'content_type' => $this->getContentType(),
44 27
            'content_encoding' => 'utf8',
45 27
            'message_id' => function($timestamp) {
46 27
                return sha1($this->getRoutingKey() . $timestamp . $this->generateBodyId() . mt_rand());
47 27
            },
48
            'user_id' => null,
49 11
            'app_id' => null,
50 27
            'delivery_mode' => self::PERSISTENT,
51 27
            'priority' => null,
52 27
            'timestamp' => function($timestamp) {
53 27
                return $timestamp;
54 27
            },
55
            'expiration' => null,
56 12
            'type' => null,
57 27
            'reply_to' => null,
58
            'correlation_id' => null,
59 27
            'headers' => function($timestamp) {
60
                return $this->packHeaders($timestamp);
61 10
            },
62
        );
63 10
    }
64 10
    
65 1
    private function generateBodyId()
66
    {
67
        if($this->body instanceof Footprintable)
68 9
        {
69
            return $this->body->footprint();
70
        }
71 1
        
72
        return uniqid(true);
73 1
    }
74
    
75
    public function canBeDroppedSilently()
76 1
    {
77
        return $this->canBeDroppedSilently;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->canBeDroppedSilently; (boolean) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::canBeDroppedSilently of type integer.

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...
78 1
    }
79
    
80 1
    public function disallowSilentDropping()
81
    {
82
        $this->canBeDroppedSilently = false;
83 27
        
84
        return $this;
85 27
    }
86
87
    public function getContentType()
88 23
    {
89
        return $this->body->getContentType();
90 23
    }
91
92
    public function getRoutingKey()
93 1
    {
94
        return $this->getAttribute('routing_key');
95 1
    }
96
97
    public function getBodyInTransportFormat()
98 5
    {
99
        return $this->body->asTransported();
100 5
    }
101 5
102
    public function setBody(Body $body)
103 5
    {
104
        $this->body = $body;
105
        $this->updateContentType();
106 14
        
107
        return $this;
108 14
    }
109 14
    
110
    private function updateContentType()
111 17
    {
112
        $this->attributes['content_type'] = $this->body->getContentType();
113 17
    }
114
115 17
    public function addHeader($headerName, $value)
116
    {
117
        $this->headers[$headerName] = $value;
118 3
119
        return $this;
120 3
    }
121
122 3
    public function addHeaders(array $headers)
123 3
    {
124
        foreach($headers as $name => $value)
125 3
        {
126
            $this->addHeader($name, $value);
127
        }
128 1
129
        return $this;
130 1
    }
131
132 1
    public function setAuthor($author)
133
    {
134
        $this->addHeader('author', $author);
135 12
136
        return $this;
137 12
    }
138
139 12
    public function packAttributes($timestamp = false)
140 12
    {
141 10
        $this->updateContentType();
142 10
        
143
        if($timestamp === false)
144 12
        {
145
            $timestamp = (new \DateTime("now"))->getTimestamp();
146 12
        }
147 12
148 12
        return array_map(function($value) use($timestamp) {
149 12
150
            if($value instanceof \Closure)
151 12
            {
152
                $value = $value($timestamp);
153 12
            }
154
155
            return $value;
156 12
157
        }, $this->attributes);
158 12
    }
159
160 12
    private function packHeaders($timestamp)
161
    {
162
        $this->headers['message_datetime'] = date('Y-m-d H:i:s', $timestamp);
163 27
164
        return $this->headers;
165 27
    }
166 27
167 27
    public function setAttribute($attributeName, $value)
168 27
    {
169 27
        if($attributeName !== 'headers')
170 27
        {
171 27
            if(array_key_exists($attributeName, $this->attributes))
172
            {
173 27
                $this->attributes[$attributeName] = $value;
174
            }
175
        }
176 5
177
        return $this;
178 5
    }
179
180 5
    public function getHeaders()
181
    {
182
        $attributes = $this->packAttributes();
183 25
184
        return $attributes['headers'];
185 25
    }
186 25
187 24
    public function getAttribute($attributeName)
188
    {
189
        if(array_key_exists($attributeName, $this->attributes))
190 1
        {
191
            return $this->attributes[$attributeName];
192
        }
193 1
194
        throw new InvalidArgumentException(sprintf('Property "%s" is unknown or is not a message property', $attributeName));
195 1
    }
196 1
197 1
    public function __toString()
198 1
    {
199 1
        return json_encode(array(
200 1
            'routing_key' => $this->getRoutingKey(),
201
            'body' => (string) $this->body,
202
            'attributes' => $this->attributes,
203 1
            'can be dropped silently' => $this->canBeDroppedSilently
204
        ));
205 1
    }
206
207 1
    public function setExpiration($expirationInSeconds)
208
    {
209 1
        $ttlInMs = 1000 * (int) $expirationInSeconds;
210
211
        $this->setAttribute('expiration', (string) $ttlInMs);
212
213
        return $this;
214
    }
215
    
216
    public function isCompressionAllowed()
217
    {
218
        return $this->allowCompression;
219
    }
220
    
221
    public function allowCompression()
222
    {
223
        $this->allowCompression = true;
224
        
225
        return $this;
226
    }
227
}
228