Completed
Push — master ( 424dcf...baf946 )
by Nicolas
02:34
created

Message::buildFromReadableMessage()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 18
cts 18
cp 1
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 13
nc 6
nop 2
crap 4
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
9
class Message implements WritableMessage
10
{
11
    use BodySetter;
12
    
13
    protected
14
        $body;
15
    
16
    private
17
        $canBeDroppedSilently,
1 ignored issue
show
Coding Style introduced by
The visibility should be declared for property $canBeDroppedSilently.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
18
        $headers,
19
        $attributes;
20
21 23
    public function __construct($routingKey = '')
22 1
    {
23 23
        $this->body = new NullBody();
24 23
        $this->canBeDroppedSilently = true;
25 23
        $this->headers = array();
26 23
        $this->initializeAttributes();
27 23
        $this->changeRoutingKey($routingKey);
28 23
    }
29
30 23
    public function changeRoutingKey($routingKey)
31
    {
32 23
        $this->setAttribute('routing_key', $routingKey);
33 23
    }
34
    
35 23
    private function initializeAttributes()
36
    {
37 23
        $this->attributes = array(
38 23
            'routing_key' => null,
39 23
            'content_type' => $this->getContentType(),
40 23
            'content_encoding' => 'utf8',
41
            'message_id' => function($timestamp) {
42 8
                return sha1($this->getRoutingKey() . $timestamp . $this->generateBodyId() . mt_rand());
43 23
            },
44 23
            'user_id' => null,
45 23
            'app_id' => null,
46 23
            'delivery_mode' => self::PERSISTENT,
47 23
            'priority' => null,
48
            'timestamp' => function($timestamp) {
49 9
                return $timestamp;
50 23
            },
51 23
            'expiration' => null,
52 23
            'type' => null,
53 23
            'reply_to' => null,
54 23
            'correlation_id' => null,
55
            'headers' => function($timestamp) {
56 10
                return $this->packHeaders($timestamp);
57 23
            },
58
        );
59 23
    }
60
    
61 8
    private function generateBodyId()
62
    {
63 8
        if($this->body instanceof Footprintable)
64 8
        {
65 1
            return $this->body->footprint();
66
        }
67
        
68 7
        return uniqid(true);
69
    }
70
    
71 1
    public function canBeDroppedSilently()
72
    {
73 1
        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...
74
    }
75
    
76 1
    public function disallowSilentDropping()
77
    {
78 1
        $this->canBeDroppedSilently = false;
79
        
80 1
        return $this;
81
    }
82
83 23
    public function getContentType()
84
    {
85 23
        return $this->body->getContentType();
86
    }
87
88 19
    public function getRoutingKey()
89
    {
90 19
        return $this->getAttribute('routing_key');
91
    }
92
93 1
    public function getBodyInTransportFormat()
94
    {
95 1
        return $this->body->asTransported();
96
    }
97
98 5
    public function setBody(Body $body)
99
    {
100 5
        $this->body = $body;
101 5
        $this->updateContentType();
102
        
103 5
        return $this;
104
    }
105
    
106 12
    private function updateContentType()
107
    {
108 12
        $this->attributes['content_type'] = $this->body->getContentType();
109 12
    }
110
111 13
    public function addHeader($headerName, $value)
112
    {
113 13
        $this->headers[$headerName] = $value;
114
115 13
        return $this;
116
    }
117
118 3
    public function addHeaders(array $headers)
119
    {
120 3
        foreach($headers as $name => $value)
121
        {
122 3
            $this->addHeader($name, $value);
123 3
        }
124
125 3
        return $this;
126
    }
127
128 1
    public function setAuthor($author)
129
    {
130 1
        $this->addHeader('author', $author);
131
132 1
        return $this;
133
    }
134
135 10
    public function packAttributes($timestamp = false)
136
    {
137 10
        $this->updateContentType();
138
        
139 10
        if($timestamp === false)
140 10
        {
141 8
            $timestamp = (new \DateTime("now"))->getTimestamp();
142 8
        }
143
144 10
        return array_map(function($value) use($timestamp) {
145
146 10
            if($value instanceof \Closure)
147 10
            {
148 10
                $value = $value($timestamp);
149 10
            }
150
151 10
            return $value;
152
153 10
        }, $this->attributes);
154
    }
155
156 10
    private function packHeaders($timestamp)
157
    {
158 10
        $this->headers['message_datetime'] = date('Y-m-d H:i:s', $timestamp);
159
160 10
        return $this->headers;
161
    }
162
163 23
    public function setAttribute($attributeName, $value)
164
    {
165 23
        if($attributeName !== 'headers')
166 23
        {
167 23
            if(array_key_exists($attributeName, $this->attributes))
168 23
            {
169 23
                $this->attributes[$attributeName] = $value;
170 23
            }
171 23
        }
172
173 23
        return $this;
174
    }
175
176 3
    public function getHeaders()
177
    {
178 3
        $attributes = $this->packAttributes();
179
180 3
        return $attributes['headers'];
181
    }
182
183 21
    public function getAttribute($attributeName)
184
    {
185 21
        if(array_key_exists($attributeName, $this->attributes))
186 21
        {
187 20
            return $this->attributes[$attributeName];
188
        }
189
190 1
        throw new InvalidArgumentException(sprintf('Property "%s" is unknown or is not a message property', $attributeName));
191
    }
192
193 1
    public function __toString()
194
    {
195 1
        return json_encode(array(
196 1
            'routing_key' => $this->getRoutingKey(),
197 1
            'body' => (string) $this->body,
198 1
            'attributes' => $this->attributes,
199 1
            'can be dropped silently' => $this->canBeDroppedSilently
200 1
        ));
201
    }
202
203 1
    public function setExpiration($expirationInSeconds)
204
    {
205 1
        $ttlInMs = 1000 * (int) $expirationInSeconds;
206
207 1
        $this->setAttribute('expiration', (string) $ttlInMs);
208
209 1
        return $this;
210
    }
211
}
212