Completed
Pull Request — master (#46)
by Nicolas
05:29
created

Message   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 243
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 6

Test Coverage

Coverage 98.06%

Importance

Changes 0
Metric Value
wmc 34
lcom 3
cbo 6
dl 0
loc 243
ccs 101
cts 103
cp 0.9806
rs 9.68
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A changeRoutingKey() 0 4 1
A initializeAttributes() 0 25 1
A generateBodyId() 0 9 2
A canBeDroppedSilently() 0 4 1
A disallowSilentDropping() 0 6 1
A getContentType() 0 9 2
A getRoutingKey() 0 4 1
A getBodyInTransportFormat() 0 4 1
A setBody() 0 7 1
A updateContentType() 0 4 1
A addHeader() 0 6 1
A addHeaders() 0 9 2
A setAuthor() 0 6 1
A packAttributes() 0 20 3
A packHeaders() 0 6 1
A setAttribute() 0 17 4
A getHeaders() 0 6 1
A getAttribute() 0 9 2
A __toString() 0 15 2
A setExpiration() 0 8 1
A isCompressionAllowed() 0 4 1
A allowCompression() 0 6 1
A isChunked() 0 4 1
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
use Puzzle\Pieces\Exceptions\JsonEncodeError;
10
use Puzzle\Pieces\Json;
11
12
class Message implements WritableMessage, ConvertibleToString
13
{
14
    public const
15
        ATTRIBUTE_CONTENT_TYPE = 'content_type';
16
17
    use BodySetter;
18
19
    private
20
        $body,
21
        $canBeDroppedSilently,
22
        $allowCompression,
23
        $userContentType,
24
        $headers,
25
        $attributes;
26
27 40
    public function __construct(string $routingKey = '')
28
    {
29 40
        $this->body = new NullBody();
30
31 40
        $this->canBeDroppedSilently = true;
32 40
        $this->allowCompression = false;
33 40
        $this->userContentType = null;
34 40
        $this->headers = array();
35 40
        $this->initializeAttributes();
36
37 40
        $this->changeRoutingKey($routingKey);
38 40
    }
39
40 40
    public function changeRoutingKey(string $routingKey): void
41
    {
42 40
        $this->setAttribute('routing_key', $routingKey);
43 40
    }
44
45 40
    private function initializeAttributes(): void
46
    {
47 40
        $this->attributes = array(
48 40
            'routing_key' => null,
49 40
            self::ATTRIBUTE_CONTENT_TYPE=> $this->getContentType(),
50 40
            'content_encoding' => 'utf8',
51
            'message_id' => function(int $timestamp) {
52 16
                return sha1($this->getRoutingKey() . $timestamp . $this->generateBodyId() . mt_rand());
53 40
            },
54
            'user_id' => null,
55
            'app_id' => null,
56 40
            'delivery_mode' => self::PERSISTENT,
57
            'priority' => null,
58
            'timestamp' => function(int $timestamp) {
59 17
                return $timestamp;
60 40
            },
61
            'expiration' => null,
62
            'type' => null,
63
            'reply_to' => null,
64
            'correlation_id' => null,
65
            'headers' => function(int $timestamp) {
66 18
                return $this->packHeaders($timestamp);
67 40
            },
68
        );
69 40
    }
70
71 16
    private function generateBodyId(): string
72
    {
73 16
        if($this->body instanceof Footprintable)
74
        {
75 3
            return $this->body->footprint();
76
        }
77
78 13
        return uniqid(true);
79
    }
80
81 1
    public function canBeDroppedSilently(): bool
82
    {
83 1
        return $this->canBeDroppedSilently;
84
    }
85
86 1
    public function disallowSilentDropping(): WritableMessage
87
    {
88 1
        $this->canBeDroppedSilently = false;
89
90 1
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMess...:disallowSilentDropping of type self.

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...
91
    }
92
93 40
    public function getContentType(): string
94
    {
95 40
        if($this->userContentType === null)
96
        {
97 40
            return $this->body->getContentType();
98
        }
99
100 3
        return $this->userContentType;
101
    }
102
103 34
    public function getRoutingKey(): string
104
    {
105 34
        return (string) $this->getAttribute('routing_key');
106
    }
107
108 8
    public function getBodyInTransportFormat()
109
    {
110 8
        return $this->body->asTransported();
111
    }
112
113 15
    public function setBody(Body $body): WritableMessage
114
    {
115 15
        $this->body = $body;
116 15
        $this->updateContentType();
117
118 15
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::setBody of type self.

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...
119
    }
120
121 24
    private function updateContentType(): void
122
    {
123 24
        $this->attributes[self::ATTRIBUTE_CONTENT_TYPE] = $this->getContentType();
124 24
    }
125
126 26
    public function addHeader(string $headerName, $value): WritableMessage
127
    {
128 26
        $this->headers[$headerName] = $value;
129
130 26
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::addHeader of type self.

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...
131
    }
132
133 9
    public function addHeaders(array $headers): WritableMessage
134
    {
135 9
        foreach($headers as $name => $value)
136
        {
137 9
            $this->addHeader($name, $value);
138
        }
139
140 9
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::addHeaders of type self.

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...
141
    }
142
143 1
    public function setAuthor(string $author): WritableMessage
144
    {
145 1
        $this->addHeader('author', $author);
146
147 1
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::setAuthor of type self.

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...
148
    }
149
150 18
    public function packAttributes(?int $timestamp = null): array
151
    {
152 18
        $this->updateContentType();
153
154 18
        if($timestamp === null)
155
        {
156 16
            $timestamp = (new \DateTime("now"))->getTimestamp();
157
        }
158
159
        return array_map(function($value) use($timestamp) {
160
161 18
            if($value instanceof \Closure)
162
            {
163 18
                $value = $value($timestamp);
164
            }
165
166 18
            return $value;
167
168 18
        }, $this->attributes);
169
    }
170
171 18
    private function packHeaders(int $timestamp): array
172
    {
173 18
        $this->headers['message_datetime'] = date('Y-m-d H:i:s', $timestamp);
174
175 18
        return $this->headers;
176
    }
177
178 40
    public function setAttribute(string $attributeName, $value): WritableMessage
179
    {
180 40
        if($attributeName !== 'headers')
181
        {
182 40
            if(array_key_exists($attributeName, $this->attributes))
183
            {
184 40
                $this->attributes[$attributeName] = $value;
185
186 40
                if($attributeName === self::ATTRIBUTE_CONTENT_TYPE)
187
                {
188 3
                    $this->userContentType = $value;
189
                }
190
            }
191
        }
192
193 40
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::setAttribute of type self.

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...
194
    }
195
196 10
    public function getHeaders(): array
197
    {
198 10
        $attributes = $this->packAttributes();
199
200 10
        return $attributes['headers'];
201
    }
202
203 36
    public function getAttribute(string $attributeName)
204
    {
205 36
        if(array_key_exists($attributeName, $this->attributes))
206
        {
207 35
            return $this->attributes[$attributeName];
208
        }
209
210 1
        throw new InvalidArgumentException(sprintf('Property "%s" is unknown or is not a message property', $attributeName));
211
    }
212
213 2
    public function __toString(): string
214
    {
215
        try {
216 2
            return (string) Json::encode([
217 2
                'routing_key' => $this->getRoutingKey(),
218 2
                'body' => (string) $this->body,
219 2
                'attributes' => $this->attributes,
220 2
                'can be dropped silently' => $this->canBeDroppedSilently
221
            ]);
222
        }
223
        catch(JsonEncodeError $e)
224
        {
225
            return sprintf('Can\'t json encode the message. error: "%s"', $e->getMessage());
226
        }
227
    }
228
229 1
    public function setExpiration(int $expirationInSeconds): WritableMessage
230
    {
231 1
        $ttlInMs = 1000 * (int) $expirationInSeconds;
232
233 1
        $this->setAttribute('expiration', (string) $ttlInMs);
234
235 1
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::setExpiration of type self.

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...
236
    }
237
238 6
    public function isCompressionAllowed(): bool
239
    {
240 6
        return $this->allowCompression;
241
    }
242
243 5
    public function allowCompression(bool $allow = true): WritableMessage
244
    {
245 5
        $this->allowCompression = (bool) $allow;
246
247 5
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (Puzzle\AMQP\Messages\Message) is incompatible with the return type declared by the interface Puzzle\AMQP\WritableMessage::allowCompression of type self.

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...
248
    }
249
250 7
    public function isChunked(): bool
251
    {
252 7
        return $this->body->isChunked();
253
    }
254
}
255