Skip to content

Commit 7762e5a

Browse files
committed
[MessageQueue]: add support for first class queue configuration
1 parent 4aa2f11 commit 7762e5a

File tree

16 files changed

+248
-24
lines changed

16 files changed

+248
-24
lines changed

app/code/Magento/Ui/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@
256256
<item name="array" xsi:type="object">arrayArgumentInterpreterProxy</item>
257257
<item name="boolean" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Boolean</item>
258258
<item name="number" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Number</item>
259+
<item name="int" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Integer</item>
259260
<item name="string" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\StringUtils</item>
260261
<item name="null" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\NullType</item>
261262
<item name="url" xsi:type="object">Magento\Ui\Config\Argument\Parser\Url</item>

app/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@
479479
<item name="array" xsi:type="object">layoutArrayArgumentReaderInterpreterProxy</item>
480480
<item name="boolean" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Boolean</item>
481481
<item name="number" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Number</item>
482+
<item name="int" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\Integer</item>
482483
<item name="string" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\StringUtils</item>
483484
<item name="null" xsi:type="object">Magento\Framework\Data\Argument\Interpreter\NullType</item>
484485
<item name="object" xsi:type="object">Magento\Framework\View\Layout\Argument\Interpreter\Passthrough</item>

lib/internal/Magento/Framework/App/ObjectManagerFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ protected function createArgumentInterpreter(
231231
'boolean' => new \Magento\Framework\Data\Argument\Interpreter\Boolean($booleanUtils),
232232
'string' => new \Magento\Framework\Data\Argument\Interpreter\BaseStringUtils($booleanUtils),
233233
'number' => new \Magento\Framework\Data\Argument\Interpreter\Number(),
234+
'int' => new \Magento\Framework\Data\Argument\Interpreter\Integer(),
234235
'null' => new \Magento\Framework\Data\Argument\Interpreter\NullType(),
235236
'object' => new \Magento\Framework\Data\Argument\Interpreter\DataObject($booleanUtils),
236237
'const' => $constInterpreter,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Framework\Data\Argument\Interpreter;
7+
8+
use Magento\Framework\Data\Argument\InterpreterInterface;
9+
10+
/**
11+
* Interpreter of numeric data, such as integer or float
12+
*/
13+
class Integer implements InterpreterInterface
14+
{
15+
/**
16+
* {@inheritdoc}
17+
* @return int|float
18+
* @throws \InvalidArgumentException
19+
*/
20+
public function evaluate(array $data)
21+
{
22+
if (!isset($data['value']) || !is_numeric($data['value'])) {
23+
throw new \InvalidArgumentException('Numeric value is expected.');
24+
}
25+
$result = $data['value'];
26+
return (int)$result;
27+
}
28+
}

lib/internal/Magento/Framework/Data/etc/argument/types.xsd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@
7373
</xs:complexContent>
7474
</xs:complexType>
7575

76+
<xs:complexType name="int">
77+
<xs:complexContent>
78+
<xs:extension base="argumentType"/>
79+
</xs:complexContent>
80+
</xs:complexType>
81+
7682
<xs:complexType name="null">
7783
<xs:complexContent>
7884
<xs:restriction base="argumentType"/>

lib/internal/Magento/Framework/MessageQueue/Topology/Config/Data.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,20 @@ public function __construct(
2323
) {
2424
parent::__construct($reader, $cache, $cacheId, $serializer);
2525
}
26+
27+
public function getQueues(): array {
28+
return array_filter($this->get(),function($item){
29+
if($item['type'] == 'queue'){
30+
return $item;
31+
}
32+
});
33+
}
34+
35+
public function getExchanges(): array {
36+
return array_filter($this->get(),function($item){
37+
if($item['type'] != 'queue'){
38+
return $item;
39+
}
40+
});
41+
}
2642
}

lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface;
99
use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding\IteratorFactory;
10+
use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding\Iterator;
11+
use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingFactory;
1012

1113
/**
1214
* {@inheritdoc}
@@ -37,7 +39,7 @@ class ExchangeConfigItem implements ExchangeConfigItemInterface
3739
/**
3840
* Exchange bindings.
3941
*
40-
* @var BindingInterface[]
42+
* @var Iterator
4143
*/
4244
private $bindings;
4345

@@ -69,6 +71,11 @@ class ExchangeConfigItem implements ExchangeConfigItemInterface
6971
*/
7072
private $isInternal;
7173

74+
/**
75+
* @var BindingFactory
76+
*/
77+
public $bindingFactory;
78+
7279
/**
7380
* Initialize dependencies.
7481
*
@@ -158,6 +165,11 @@ public function setData(array $data)
158165
$this->isDurable = $data['durable'];
159166
$this->isAutoDelete = $data['autoDelete'];
160167
$this->arguments = $data['arguments'];
161-
$this->bindings->setData($data['bindings']);
168+
if( $this->type != 'queue'){
169+
$this->bindings->setData($data['bindings']);
170+
}
171+
else{
172+
$this->bindings->setData([]);
173+
}
162174
}
163175
}

lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Iterator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Iterator implements \Iterator, \ArrayAccess
3636
*/
3737
public function __construct(Data $configData, ExchangeConfigItemFactory $itemFactory)
3838
{
39-
$this->data = $configData->get();
39+
$this->data = $configData->getExchanges();
4040
$this->object = $itemFactory->create();
4141
$this->rewind();
4242
}

lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/DataMapper.php

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?php
2+
23
/**
34
* Copyright © Magento, Inc. All rights reserved.
45
* See COPYING.txt for license details.
56
*/
7+
68
namespace Magento\Framework\MessageQueue\Topology\Config\QueueConfigItem;
79

810
use Magento\Framework\MessageQueue\Topology\Config\Data;
@@ -64,16 +66,22 @@ public function getMappedData()
6466
{
6567
if (null === $this->mappedData) {
6668
$this->mappedData = [];
67-
foreach ($this->configData->get() as $exchange) {
69+
70+
$queues = $this->createQueueItemsFromQueues($this->configData->getQueues());
71+
foreach ($queues as $key => $value) {
72+
$this->mappedData[$key] = $value;
73+
}
74+
foreach ($this->configData->getExchanges() as $exchange) {
6875
$connection = $exchange['connection'];
6976
foreach ($exchange['bindings'] as $binding) {
70-
if ($binding['destinationType'] === 'queue') {
77+
if ($binding['destinationType'] === 'queue' && !array_key_exists($binding['destination'] . '--' . $connection, $this->mappedData)) {
7178
$queueItems = $this->createQueueItems($binding['destination'], $binding['topic'], $connection);
7279
$this->mappedData = array_merge($this->mappedData, $queueItems);
7380
}
7481
}
7582
}
7683
}
84+
7785
return $this->mappedData;
7886
}
7987

@@ -83,13 +91,54 @@ public function getMappedData()
8391
* @param string $name
8492
* @param string $topic
8593
* @param string $connection
94+
* @deprecated
8695
* @return array
8796
*/
8897
private function createQueueItems($name, $topic, $connection)
98+
{
99+
return $this->createQueueItemsFromTopic($name, $topic, $connection);
100+
}
101+
102+
private function createQueueItemsFromQueues(array $queues)
89103
{
90104
$output = [];
91-
$synchronousTopics = [];
105+
foreach ($queues as $queue) {
106+
$output[$queue['name'] . '--' . $queue['connection']] =
107+
$this->createQueue(
108+
$queue['name'],
109+
$queue['connection'],
110+
$queue['arguments'],
111+
$queue['durable'],
112+
$queue['autoDelete']
113+
);
114+
}
115+
return $output;
116+
}
92117

118+
private function createQueue($name, $connection, $arguments = [], $durable = true, $autoDelete = false)
119+
{
120+
return [
121+
'name' => $name,
122+
'connection' => $connection,
123+
'durable' => isset($durable) ? $durable : true,
124+
'autoDelete' => isset($autoDelete) ? $autoDelete : false,
125+
'arguments' => isset($arguments) ? $arguments : [],
126+
];
127+
}
128+
129+
/**
130+
* Create queue config item.
131+
*
132+
* @param string $name
133+
* @param string $topic
134+
* @param string $connection
135+
* @return array
136+
*/
137+
private function createQueueItemsFromTopic($name, $topic, $connection)
138+
{
139+
$output = [];
140+
$synchronousTopics = [];
141+
93142
if (strpos($topic, '*') !== false || strpos($topic, '#') !== false) {
94143
$synchronousTopics = $this->matchSynchronousTopics($topic);
95144
} elseif ($this->isSynchronousTopic($topic)) {

lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/DependentFields.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?php
2+
23
/**
34
* Copyright © Magento, Inc. All rights reserved.
45
* See COPYING.txt for license details.
56
*/
7+
68
namespace Magento\Framework\MessageQueue\Topology\Config\Validator;
79

810
use Magento\Framework\MessageQueue\Topology\Config\ValidatorInterface;
@@ -19,9 +21,11 @@ public function validate($configData)
1921
{
2022
$errors = [];
2123
foreach ($configData as $name => $data) {
22-
foreach ((array)$data['bindings'] as $binding) {
23-
if (isset($data['type']) && $data['type'] == 'topic' && !isset($binding['topic'])) {
24-
$errors[] = 'Topic name is required for topic based exchange: ' . $name;
24+
if ($data['type'] != 'queue') {
25+
foreach ((array)$data['bindings'] as $binding) {
26+
if (isset($data['type']) && $data['type'] == 'topic' && !isset($binding['topic'])) {
27+
$errors[] = 'Topic name is required for topic based exchange: ' . $name;
28+
}
2529
}
2630
}
2731
}

lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/FieldsTypes.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class FieldsTypes implements ValidatorInterface
1818
public function validate($configData)
1919
{
2020
foreach ($configData as $exchangeName => $exchangeConfig) {
21-
$this->validateFieldsTypes($exchangeName, $exchangeConfig);
21+
$exchangeConfig['type'] != 'queue' ?
22+
$this->validateFieldsTypes($exchangeName, $exchangeConfig) : $this->validateQueueTypes($exchangeName, $exchangeConfig);
2223
}
2324
}
2425

@@ -128,4 +129,16 @@ private function validateBindings($exchangeName, $exchangeConfig, $bindingFields
128129
}
129130
}
130131
}
132+
133+
/**
134+
* Make sure types of all fields in the queue item config are correct.
135+
*
136+
* @param string $queueName
137+
* @param array $queueConfig
138+
* @return void
139+
* @throws \LogicException
140+
*/
141+
private function validateQueueTypes($queueName, $queueConfig)
142+
{
143+
}
131144
}

lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/Format.php

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?php
2+
23
/**
34
* Copyright © Magento, Inc. All rights reserved.
45
* See COPYING.txt for license details.
56
*/
7+
68
namespace Magento\Framework\MessageQueue\Topology\Config\Validator;
79

810
use Magento\Framework\MessageQueue\Topology\Config\ValidatorInterface;
@@ -17,24 +19,34 @@ class Format implements ValidatorInterface
1719
*/
1820
public function validate($configData)
1921
{
20-
$requiredFields = ['name', 'type', 'connection', 'durable', 'autoDelete', 'internal', 'bindings', 'arguments'];
22+
$requiredExchangeFields = ['name', 'type', 'connection', 'durable', 'autoDelete', 'internal', 'bindings', 'arguments'];
23+
$requiredQueueFields = ['name', 'type', 'connection', 'durable', 'autoDelete', 'internal', 'arguments'];
24+
2125
$requiredBindingFields = ['id', 'destinationType', 'destination', 'disabled', 'topic', 'arguments'];
2226
$errors = [];
2327
foreach ($configData as $name => $data) {
24-
$diff = array_diff($requiredFields, array_keys($data));
25-
foreach ($diff as $field) {
26-
$errors[] = sprintf('Missing [%s] field for exchange %s.', $field, $name);
27-
}
28+
if ($data['type'] != 'queue') {
29+
$diff = array_diff($requiredExchangeFields, array_keys($data));
30+
foreach ($diff as $field) {
31+
$errors[] = sprintf('Missing [%s] field for exchange %s.', $field, $name);
32+
}
2833

29-
if (!array_key_exists('bindings', $data) || !is_array($data['bindings'])) {
30-
$errors[] = sprintf('Invalid bindings format for exchange %s.', $name);
31-
continue;
32-
}
34+
if (!array_key_exists('bindings', $data) || !is_array($data['bindings'])) {
35+
$errors[] = sprintf('Invalid bindings format for exchange %s.', $name);
36+
continue;
37+
}
3338

34-
foreach ($data['bindings'] as $bindingConfig) {
35-
$diff = array_diff($requiredBindingFields, array_keys($bindingConfig));
39+
foreach ($data['bindings'] as $bindingConfig) {
40+
$diff = array_diff($requiredBindingFields, array_keys($bindingConfig));
41+
foreach ($diff as $field) {
42+
$errors[] = sprintf('Missing [%s] field for binding %s in exchange config.', $field, $name);
43+
}
44+
}
45+
}
46+
else{
47+
$diff = array_diff($requiredQueueFields, array_keys($data));
3648
foreach ($diff as $field) {
37-
$errors[] = sprintf('Missing [%s] field for binding %s in exchange config.', $field, $name);
49+
$errors[] = sprintf('Missing [%s] field for queue %s.', $field, $name);
3850
}
3951
}
4052
}

lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Converter.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,41 @@ public function convert($source)
9999
'arguments' => $exchangeArguments,
100100
];
101101
}
102+
103+
foreach ($source->getElementsByTagName('queue') as $queue) {
104+
$name = $this->getAttributeValue($queue, 'name');
105+
$connection = $this->getAttributeValue($queue, 'connection');
106+
107+
$bindings = [];
108+
$queueArguments = [];
109+
/** @var \DOMNode $node */
110+
foreach ($queue->childNodes as $node) {
111+
if (!in_array($node->nodeName, ['binding', 'arguments']) || $node->nodeType != XML_ELEMENT_NODE) {
112+
continue;
113+
}
114+
switch ($node->nodeName) {
115+
case 'binding':
116+
$bindings = $this->processBindings($node, $bindings);
117+
break;
118+
119+
case 'arguments':
120+
$queueArguments = $this->processArguments($node);
121+
break;
122+
}
123+
}
124+
125+
$autoDelete = $this->getAttributeValue($queue, 'autoDelete', false);
126+
$result[$name . '--' . $connection] = [
127+
'name' => $name,
128+
'type' => $this->getAttributeValue($queue, 'type'),
129+
'connection' => $connection,
130+
'durable' => $this->booleanUtils->toBoolean($this->getAttributeValue($queue, 'durable', true)),
131+
'autoDelete' => $this->booleanUtils->toBoolean($autoDelete),
132+
'internal' => $this->booleanUtils->toBoolean($this->getAttributeValue($queue, 'internal', false)),
133+
'arguments' => $queueArguments,
134+
];
135+
}
136+
102137
return $result;
103138
}
104139

lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Reader.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem implements Read
2222
'/config/exchange/binding' => 'id',
2323
'/config/exchange/binding/arguments/argument' => 'name',
2424
'/config/exchange/binding/arguments/argument(/item)+' => 'name',
25+
'/config/queue' => ['name', 'connection'],
26+
'/config/queue/arguments/argument' => 'name',
27+
'/config/queue/arguments/argument(/item)+' => 'name'
2528
];
2629

2730
/**

0 commit comments

Comments
 (0)