Skip to content

Commit deef5e8

Browse files
authored
Merge pull request #11 from apacheborys/introduce-factory
introduce factory, reduce size of AbstractHandler
2 parents 788c577 + 036b24f commit deef5e8

7 files changed

Lines changed: 191 additions & 137 deletions

File tree

psalm.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@
2121
</PossiblyInvalidPropertyAssignmentValue>
2222
<PossiblyInvalidArgument>
2323
<errorLevel type="suppress">
24-
<file name="src/AbstractHandler.php" />
24+
<file name="src/HandlerFactory.php" />
2525
</errorLevel>
2626
</PossiblyInvalidArgument>
2727
<MoreSpecificReturnType>
2828
<errorLevel type="suppress">
29-
<file name="src/AbstractHandler.php" />
29+
<file name="src/HandlerFactory.php" />
3030
</errorLevel>
3131
</MoreSpecificReturnType>
3232
<InvalidStringClass>
3333
<errorLevel type="suppress">
34-
<file name="src/AbstractHandler.php" />
34+
<file name="src/HandlerFactory.php" />
3535
</errorLevel>
3636
</InvalidStringClass>
3737
<LessSpecificReturnStatement>
3838
<errorLevel type="suppress">
39-
<file name="src/AbstractHandler.php" />
39+
<file name="src/HandlerFactory.php" />
4040
</errorLevel>
4141
</LessSpecificReturnStatement>
4242
</issueHandlers>

src/AbstractHandler.php

Lines changed: 3 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -4,148 +4,25 @@
44
namespace ApacheBorys\Retry;
55

66
use ApacheBorys\Retry\Entity\Config;
7-
use ApacheBorys\Retry\HandlerExceptionDeclarator\StandardHandlerExceptionDeclarator;
8-
use ApacheBorys\Retry\Interfaces\Executor;
97
use ApacheBorys\Retry\Interfaces\HandlerExceptionDeclaratorInterface;
10-
use ApacheBorys\Retry\Interfaces\Transport;
118
use ApacheBorys\Retry\Traits\LogWrapper;
12-
use Psr\Container\ContainerInterface;
139
use Psr\Log\LoggerInterface;
14-
use Psr\Log\LogLevel;
1510

1611
abstract class AbstractHandler
1712
{
18-
public const LOG_PREFIX = 'Retry lib: ';
19-
2013
use LogWrapper;
2114

2215
/** @var Config[] */
2316
protected array $config;
2417

2518
protected ?LoggerInterface $logger;
2619

27-
protected ?ContainerInterface $container;
28-
2920
protected HandlerExceptionDeclaratorInterface $declarator;
3021

31-
public function __construct(array $config = [], LoggerInterface $logger = null, ContainerInterface $container = null)
22+
public function __construct(array $config, HandlerExceptionDeclaratorInterface $declarator, LoggerInterface $logger = null)
3223
{
3324
$this->logger = $logger;
34-
$this->container = $container;
35-
$this->config = $this->initConfig($config);
36-
}
37-
38-
/**
39-
* @param array $config
40-
* @return Config[]
41-
* @psalm-suppress ArgumentTypeCoercion
42-
* @psalm-suppress PropertyTypeCoercion
43-
*/
44-
private function initConfig(array $config): array
45-
{
46-
$result = [];
47-
48-
$this->declarator = $this->instantiateClass(
49-
$config['handlerExceptionDeclarator']['class'] ?? StandardHandlerExceptionDeclarator::class,
50-
$config['handlerExceptionDeclarator']['arguments'] ?? [],
51-
HandlerExceptionDeclaratorInterface::class
52-
);
53-
54-
$this->sendLogRecordInitDeclarator(get_class($this->declarator));
55-
56-
foreach ($config['items'] as $retryName => $configNode) {
57-
$result[$retryName] = new Config(
58-
(string) $retryName,
59-
(string) $configNode['exception'],
60-
(int) $configNode['maxRetries'],
61-
$configNode['formula'],
62-
$this->instantiateClass(
63-
$configNode['transport']['class'],
64-
$configNode['transport']['arguments'] ?? [],
65-
Transport::class
66-
),
67-
$this->instantiateClass(
68-
$configNode['executor']['class'],
69-
$configNode['executor']['arguments'] ?? [],
70-
Executor::class
71-
)
72-
);
73-
}
74-
75-
$this->sendLogRecordInitConfigs(count($result));
76-
77-
return $result;
78-
}
79-
80-
private function sendLogRecordInitDeclarator(string $declaratorClass): void
81-
{
82-
$this->sendLogRecord(
83-
LogLevel::INFO,
84-
sprintf('Init for %s with handler exception declarator %s', get_class($this), $declaratorClass)
85-
);
86-
}
87-
88-
private function sendLogRecordInitConfigs(int $qty): void
89-
{
90-
$this->sendLogRecord(LogLevel::INFO, sprintf('Init for %s configs. Quantity: %d', get_class($this), $qty));
91-
}
92-
93-
private function compileArguments(array $arguments): array
94-
{
95-
$result = [];
96-
97-
foreach ($arguments as $arg) {
98-
if (is_string($arg)) {
99-
$tempResult = $this->checkClassInContainer($arg);
100-
101-
if (!is_null($tempResult)) {
102-
$result[] = $tempResult;
103-
continue;
104-
}
105-
}
106-
107-
if (is_array($arg) && isset($arg['class'], $arg['arguments'])) {
108-
$result[] = new $arg['class'](...$this->compileArguments($arg['arguments']));
109-
continue;
110-
}
111-
112-
$result[] = $arg;
113-
}
114-
115-
return $result;
116-
}
117-
118-
/**
119-
* @return HandlerExceptionDeclaratorInterface|Transport|Executor
120-
*/
121-
private function instantiateClass(string $class, array $arguments, string $shouldBeInstanceOf): object
122-
{
123-
$result = $this->checkClassInContainer($class) ?? new $class(...$this->compileArguments($arguments));
124-
125-
if (!($result instanceof $shouldBeInstanceOf)) {
126-
throw new \LogicException(
127-
sprintf('The generated class %s is not an inctance of %', get_class($result), $shouldBeInstanceOf)
128-
);
129-
}
130-
131-
return $result;
132-
}
133-
134-
private function checkClassInContainer(string $class): ?object
135-
{
136-
if ($class[0] === '@') {
137-
if ($this->container instanceof ContainerInterface && $this->container->has(substr($class, 1))) {
138-
return $this->container->get(substr($class, 1));
139-
} else {
140-
throw new \LogicException(
141-
sprintf(
142-
'Can\'t get %s instance from container to instantiate Transport or Executor',
143-
substr($class, 1)
144-
)
145-
);
146-
}
147-
}
148-
149-
return null;
25+
$this->declarator = $declarator;
26+
$this->config = $config;
15027
}
15128
}

src/HandlerFactory.php

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ApacheBorys\Retry;
6+
7+
use ApacheBorys\Retry\Entity\Config;
8+
use ApacheBorys\Retry\HandlerExceptionDeclarator\StandardHandlerExceptionDeclarator;
9+
use ApacheBorys\Retry\Interfaces\Executor;
10+
use ApacheBorys\Retry\Interfaces\HandlerExceptionDeclaratorInterface;
11+
use ApacheBorys\Retry\Interfaces\Transport;
12+
use ApacheBorys\Retry\Traits\LogWrapper;
13+
use Psr\Container\ContainerExceptionInterface;
14+
use Psr\Container\ContainerInterface;
15+
use Psr\Container\NotFoundExceptionInterface;
16+
use Psr\Log\LoggerInterface;
17+
use Psr\Log\LogLevel;
18+
19+
class HandlerFactory
20+
{
21+
use LogWrapper;
22+
23+
private array $config;
24+
25+
private ?LoggerInterface $logger;
26+
27+
public function __construct(array $config, LoggerInterface $logger = null)
28+
{
29+
$this->config = $config;
30+
$this->logger = $logger;
31+
}
32+
33+
public function createExceptionHandler(?ContainerInterface $container = null): ExceptionHandler
34+
{
35+
return new ExceptionHandler($this->compileConfig($container), $this->instantiateDeclarator($container), $this->logger);
36+
}
37+
38+
public function createMessageHandler(?ContainerInterface $container = null): MessageHandler
39+
{
40+
return new MessageHandler($this->compileConfig($container), $this->instantiateDeclarator($container), $this->logger);
41+
}
42+
43+
/**
44+
* @return Config[]
45+
* @psalm-suppress ArgumentTypeCoercion
46+
* @psalm-suppress PropertyTypeCoercion
47+
*/
48+
private function compileConfig(?ContainerInterface $container): array
49+
{
50+
$result = [];
51+
52+
foreach ($this->config['items'] as $retryName => $configNode) {
53+
$result[$retryName] = new Config(
54+
(string) $retryName,
55+
(string) $configNode['exception'],
56+
(int) $configNode['maxRetries'],
57+
$configNode['formula'],
58+
$this->instantiateClass(
59+
$configNode['transport']['class'],
60+
$configNode['transport']['arguments'] ?? [],
61+
Transport::class,
62+
$container
63+
),
64+
$this->instantiateClass(
65+
$configNode['executor']['class'],
66+
$configNode['executor']['arguments'] ?? [],
67+
Executor::class,
68+
$container
69+
)
70+
);
71+
}
72+
73+
$this->sendLogRecordInitConfigs(count($result));
74+
75+
return $result;
76+
}
77+
78+
private function instantiateDeclarator(?ContainerInterface $container): HandlerExceptionDeclaratorInterface
79+
{
80+
/** @var HandlerExceptionDeclaratorInterface $declarator */
81+
$declarator = $this->instantiateClass(
82+
$this->config['handlerExceptionDeclarator']['class'] ?? StandardHandlerExceptionDeclarator::class,
83+
$this->config['handlerExceptionDeclarator']['arguments'] ?? [],
84+
HandlerExceptionDeclaratorInterface::class,
85+
$container
86+
);
87+
88+
$this->sendLogRecordInitDeclarator(get_class($declarator));
89+
90+
return $declarator;
91+
}
92+
93+
private function sendLogRecordInitDeclarator(string $declaratorClass): void
94+
{
95+
$this->sendLogRecord(
96+
LogLevel::INFO,
97+
sprintf('Init for %s with handler exception declarator %s', get_class($this), $declaratorClass)
98+
);
99+
}
100+
101+
private function sendLogRecordInitConfigs(int $qty): void
102+
{
103+
$this->sendLogRecord(LogLevel::INFO, sprintf('Init for %s configs. Quantity: %d', get_class($this), $qty));
104+
}
105+
106+
private function compileArguments(array $arguments, ?ContainerInterface $container): array
107+
{
108+
$result = [];
109+
110+
foreach ($arguments as $arg) {
111+
if (is_string($arg)) {
112+
$tempResult = $this->checkClassInContainer($arg, $container);
113+
114+
if (!is_null($tempResult)) {
115+
$result[] = $tempResult;
116+
continue;
117+
}
118+
}
119+
120+
if (is_array($arg) && isset($arg['class'], $arg['arguments'])) {
121+
$result[] = new $arg['class'](...$this->compileArguments($arg['arguments'], $container));
122+
continue;
123+
}
124+
125+
$result[] = $arg;
126+
}
127+
128+
return $result;
129+
}
130+
131+
/**
132+
* @return HandlerExceptionDeclaratorInterface|Transport|Executor
133+
*/
134+
private function instantiateClass(
135+
string $class,
136+
array $arguments,
137+
string $shouldBeInstanceOf,
138+
?ContainerInterface $container
139+
): object {
140+
$result = $this->checkClassInContainer($class, $container) ?? new $class(...$this->compileArguments($arguments, $container));
141+
142+
if (!($result instanceof $shouldBeInstanceOf)) {
143+
throw new \LogicException(
144+
sprintf('The generated class %s is not an inctance of %', get_class($result), $shouldBeInstanceOf)
145+
);
146+
}
147+
148+
return $result;
149+
}
150+
151+
/**
152+
* @throws ContainerExceptionInterface
153+
* @throws NotFoundExceptionInterface
154+
*/
155+
private function checkClassInContainer(string $class, ?ContainerInterface $container): ?object
156+
{
157+
if ($class[0] === '@') {
158+
if ($container instanceof ContainerInterface && $container->has(substr($class, 1))) {
159+
return $container->get(substr($class, 1));
160+
} else {
161+
throw new \LogicException(
162+
sprintf(
163+
'Can\'t get %s instance from container to instantiate Transport or Executor',
164+
substr($class, 1)
165+
)
166+
);
167+
}
168+
}
169+
170+
return null;
171+
}
172+
}

src/Traits/LogWrapper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ trait LogWrapper
1010
protected function sendLogRecord(string $level, string $string): void
1111
{
1212
if ($this->logger instanceof LoggerInterface) {
13-
$this->logger->{$level}(self::LOG_PREFIX . $string);
13+
$this->logger->{$level}('Retry lib: ' . $string);
1414
}
1515
}
1616
}

tests/Functional/FunctionalTest.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace ApacheBorys\Retry\Tests\Functional;
55

66
use ApacheBorys\Retry\HandlerExceptionDeclarator\StandardHandlerExceptionDeclarator;
7+
use ApacheBorys\Retry\HandlerFactory;
78
use ApacheBorys\Retry\MessageHandler;
89
use ApacheBorys\Retry\Tests\Functional\Container\FakeContainer;
910
use ApacheBorys\Retry\Tests\Functional\Logger\FakeLogger;
@@ -30,7 +31,8 @@ public function testExecution(): void
3031
$this->assertEquals(1, $this->howManyUnprocessedMessagesInDb($pdo));
3132

3233
$config = json_decode(file_get_contents($configFile), true);
33-
$worker = new MessageHandler($config);
34+
$factory = new HandlerFactory($config);
35+
$worker = $factory->createMessageHandler();
3436
$worker->processRetries(['Some\\Fake\\Class']);
3537

3638
$this->assertEquals(1, $this->howManyMessagesInDb($pdo));
@@ -72,7 +74,8 @@ public function testExecutionWithContainer(): void
7274
$this->assertEquals(1, $this->howManyUnprocessedMessagesInDb($pdo));
7375

7476
$config = json_decode(file_get_contents($configFile), true);
75-
$worker = new MessageHandler($config, null, $container);
77+
$factory = new HandlerFactory($config);
78+
$worker = $factory->createMessageHandler($container);
7679
$worker->processRetries(['Some\\Fake\\Class']);
7780

7881
$this->assertEquals(1, $this->howManyMessagesInDb($pdo));

0 commit comments

Comments
 (0)