1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | |||
4 | namespace HeroesofAbenez\Chat\DI; |
||
5 | |||
6 | use HeroesofAbenez\Chat\ChatCommandsProcessor; |
||
7 | use HeroesofAbenez\Chat\IChatCommand; |
||
8 | use HeroesofAbenez\Chat\ChatControl; |
||
9 | use HeroesofAbenez\Chat\NewChatMessageFormFactory; |
||
10 | use HeroesofAbenez\Chat\IChatMessageProcessor; |
||
11 | use HeroesofAbenez\Chat\IDatabaseAdapter; |
||
12 | use Nette\DI\MissingServiceException; |
||
13 | use HeroesofAbenez\Chat\InvalidChatControlFactoryException; |
||
14 | use HeroesofAbenez\Chat\InvalidMessageProcessorException; |
||
15 | use HeroesofAbenez\Chat\InvalidDatabaseAdapterException; |
||
16 | use Nette\Schema\Expect; |
||
17 | use Nette\DI\Definitions\FactoryDefinition; |
||
18 | use Nette\DI\Definitions\ServiceDefinition; |
||
19 | |||
20 | /** |
||
21 | * ChatExtension |
||
22 | * |
||
23 | * @author Jakub Konečný |
||
24 | */ |
||
25 | final class ChatExtension extends \Nette\DI\CompilerExtension { |
||
26 | /** @internal */ |
||
27 | public const SERVICE_CHAT_COMMANDS_PROCESSOR = "commandsProcessor"; |
||
28 | /** @internal */ |
||
29 | public const SERVICE_DATABASE_ADAPTER = "databaseAdapter"; |
||
30 | /** @internal */ |
||
31 | public const SERVICE_NEW_MESSAGE_FORM = "newMessageForm"; |
||
32 | /** @internal */ |
||
33 | public const TAG_CHAT = "chat.chat"; |
||
34 | /** @var \stdClass */ |
||
35 | protected $config; |
||
36 | |||
37 | public function getConfigSchema(): \Nette\Schema\Schema { |
||
38 | 1 | return Expect::structure([ |
|
39 | 1 | "chats" => Expect::arrayOf("interface")->default([])->required(), |
|
40 | 1 | "messageProcessors" => Expect::arrayOf("class")->default([ |
|
41 | 1 | self::SERVICE_CHAT_COMMANDS_PROCESSOR => ChatCommandsProcessor::class, |
|
42 | ]), |
||
43 | 1 | "databaseAdapter" => Expect::type("class")->required(), |
|
44 | 1 | "characterProfileLink" => Expect::string(""), |
|
45 | ]); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * @throws InvalidChatControlFactoryException |
||
50 | */ |
||
51 | protected function validateFactory(string $interface): void { |
||
52 | try { |
||
53 | 1 | $rm = new \ReflectionMethod($interface, "create"); |
|
54 | 1 | } catch(\ReflectionException $e) { |
|
55 | 1 | throw new InvalidChatControlFactoryException("Interface $interface does not contain method create.", 0, $e); |
|
56 | } |
||
57 | 1 | $returnType = $rm->getReturnType(); |
|
58 | 1 | if($returnType === null || !is_subclass_of($returnType->getName(), ChatControl::class)) { |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
59 | 1 | throw new InvalidChatControlFactoryException("Return type of $interface::create() is not a subtype of " . ChatControl::class . "."); |
|
0 ignored issues
–
show
|
|||
60 | } |
||
61 | 1 | } |
|
62 | |||
63 | /** |
||
64 | * @throws InvalidChatControlFactoryException |
||
65 | */ |
||
66 | protected function getChats(): array { |
||
67 | 1 | $chats = []; |
|
68 | 1 | foreach($this->config->chats as $name => $interface) { |
|
69 | 1 | $this->validateFactory($interface); |
|
70 | 1 | $chats[$name] = $interface; |
|
71 | } |
||
72 | 1 | return $chats; |
|
73 | } |
||
74 | |||
75 | /** |
||
76 | * @throws InvalidMessageProcessorException |
||
77 | */ |
||
78 | protected function getMessageProcessors(): array { |
||
79 | 1 | $messageProcessors = []; |
|
80 | 1 | foreach($this->config->messageProcessors as $name => $processor) { |
|
81 | 1 | if(!is_subclass_of($processor, IChatMessageProcessor::class)) { |
|
82 | 1 | throw new InvalidMessageProcessorException("Invalid message processor $processor."); |
|
83 | } |
||
84 | 1 | $messageProcessors[$name] = $processor; |
|
85 | } |
||
86 | 1 | return $messageProcessors; |
|
87 | } |
||
88 | |||
89 | /** |
||
90 | * @throws InvalidDatabaseAdapterException |
||
91 | */ |
||
92 | protected function getDatabaseAdapter(): string { |
||
93 | /** @var string $adapter */ |
||
94 | 1 | $adapter = $this->config->databaseAdapter; |
|
95 | 1 | if(!is_subclass_of($adapter, IDatabaseAdapter::class)) { |
|
96 | 1 | throw new InvalidDatabaseAdapterException("Invalid database adapter $adapter."); |
|
97 | } |
||
98 | 1 | return $adapter; |
|
99 | } |
||
100 | |||
101 | /** |
||
102 | * @throws InvalidChatControlFactoryException |
||
103 | * @throws InvalidMessageProcessorException |
||
104 | * @throws InvalidDatabaseAdapterException |
||
105 | */ |
||
106 | public function loadConfiguration(): void { |
||
107 | 1 | $builder = $this->getContainerBuilder(); |
|
108 | 1 | $chats = $this->getChats(); |
|
109 | /** @var string $characterProfileLink */ |
||
110 | 1 | $characterProfileLink = $this->config->characterProfileLink; |
|
111 | 1 | foreach($chats as $name => $interface) { |
|
112 | 1 | $chat = $builder->addFactoryDefinition($this->prefix($name)) |
|
113 | 1 | ->setImplement($interface) |
|
114 | 1 | ->addTag(static::TAG_CHAT); |
|
115 | 1 | if($characterProfileLink !== "") { |
|
116 | 1 | $chat->getResultDefinition()->addSetup("setCharacterProfileLink", [$characterProfileLink]); |
|
117 | } |
||
118 | } |
||
119 | 1 | $messageProcessors = $this->getMessageProcessors(); |
|
120 | 1 | foreach($messageProcessors as $name => $processor) { |
|
121 | 1 | $builder->addDefinition($this->prefix($name)) |
|
122 | 1 | ->setType($processor); |
|
123 | } |
||
124 | 1 | $databaseAdapter = $this->getDatabaseAdapter(); |
|
125 | 1 | $builder->addDefinition($this->prefix(static::SERVICE_DATABASE_ADAPTER)) |
|
126 | 1 | ->setType($databaseAdapter); |
|
127 | 1 | $builder->addDefinition($this->prefix(static::SERVICE_NEW_MESSAGE_FORM)) |
|
128 | 1 | ->setType(NewChatMessageFormFactory::class); |
|
129 | 1 | } |
|
130 | |||
131 | protected function registerMessageProcessors(): void { |
||
132 | 1 | $builder = $this->getContainerBuilder(); |
|
133 | 1 | $chats = $this->getChats(); |
|
134 | 1 | $messageProcessors = $this->getMessageProcessors(); |
|
135 | 1 | foreach($chats as $chat => $chatClass) { |
|
136 | /** @var FactoryDefinition $chatService */ |
||
137 | 1 | $chatService = $builder->getDefinition($this->prefix($chat)); |
|
138 | 1 | foreach($messageProcessors as $processor => $processorClass) { |
|
139 | 1 | $processorService = $builder->getDefinition($this->prefix($processor)); |
|
140 | 1 | $chatService->getResultDefinition()->addSetup("addMessageProcessor", [$processorService]); |
|
141 | } |
||
142 | } |
||
143 | 1 | } |
|
144 | |||
145 | protected function registerChatCommands(): void { |
||
146 | 1 | $builder = $this->getContainerBuilder(); |
|
147 | try { |
||
148 | /** @var ServiceDefinition $processor */ |
||
149 | 1 | $processor = $builder->getDefinition($this->prefix(static::SERVICE_CHAT_COMMANDS_PROCESSOR)); |
|
150 | } catch(MissingServiceException $e) { |
||
151 | return; |
||
152 | } |
||
153 | 1 | $chatCommands = $builder->findByType(IChatCommand::class); |
|
154 | 1 | foreach($chatCommands as $command) { |
|
155 | 1 | $processor->addSetup("addCommand", [$command]); |
|
156 | } |
||
157 | 1 | } |
|
158 | |||
159 | public function beforeCompile(): void { |
||
160 | 1 | $this->registerMessageProcessors(); |
|
161 | 1 | $this->registerChatCommands(); |
|
162 | 1 | } |
|
163 | } |
||
164 | ?> |