Completed
Push — master ( de3407...601a68 )
by Jakub
02:26
created

ChatExtension::getCharacterProfileLink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
crap 1
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 Nette\Utils\Validators;
9
use HeroesofAbenez\Chat\ChatControl;
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
17
/**
18
 * ChatExtension
19
 *
20
 * @author Jakub Konečný
21
 */
22 1
final class ChatExtension extends \Nette\DI\CompilerExtension {
23
  /** @internal */
24
  public const SERVICE_CHAT_COMMANDS_PROCESSOR = "commandsProcessor";
25
  /** @internal */
26
  public const SERVICE_DATABASE_ADAPTER = "databaseAdapter";
27
  /** @internal */
28
  public const TAG_CHAT = "chat.chat";
29
  
30
  protected $defaults = [
31
    "chats" => [],
32
    "messageProcessors" => [
33
      self::SERVICE_CHAT_COMMANDS_PROCESSOR => ChatCommandsProcessor::class,
34
    ],
35
    "databaseAdapter" => "",
36
    "characterProfileLink" => "",
37
  ];
38
  
39
  /**
40
   * @throws InvalidChatControlFactoryException
41
   */
42
  protected function validateFactory(string $interface): void {
43
    try {
44 1
      $rc = new \ReflectionClass($interface);
45 1
    } catch(\ReflectionException $e) {
46 1
      throw new InvalidChatControlFactoryException("Interface $interface not found.", 0, $e);
47
    }
48 1
    if(!$rc->isInterface()) {
49 1
      throw new InvalidChatControlFactoryException("$interface is not an interface.");
50
    }
51
    try {
52 1
      $rm = new \ReflectionMethod($interface, "create");
53 1
    } catch(\ReflectionException $e) {
54 1
      throw new InvalidChatControlFactoryException("Interface $interface does not contain method create.", 0, $e);
55
    }
56 1
    $returnType = $rm->getReturnType();
57 1
    if(is_null($returnType) OR !is_subclass_of($returnType->getName(), ChatControl::class)) {
58 1
      throw new InvalidChatControlFactoryException("Return type of $interface::create() is not a subtype of " . ChatControl::class . ".");
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 138 characters
Loading history...
59
    }
60 1
  }
61
  
62
  /**
63
   * @throws \Nette\Utils\AssertionException
64
   * @throws InvalidChatControlFactoryException
65
   */
66
  protected function getChats(): array {
67 1
    $chats = [];
68 1
    $config = $this->getConfig($this->defaults);
69 1
    Validators::assertField($config, "chats", "array");
70 1
    foreach($config["chats"] as $name => $interface) {
71 1
      $this->validateFactory($interface);
72 1
      $chats[$name] = $interface;
73
    }
74 1
    return $chats;
75
  }
76
  
77
  /**
78
   * @throws \Nette\Utils\AssertionException
79
   */
80
  protected function getCharacterProfileLink(): string {
81 1
    $config = $this->getConfig($this->defaults);
82 1
    Validators::assertField($config, "characterProfileLink", "string");
83 1
    return $config["characterProfileLink"];
84
  }
85
  
86
  /**
87
   * @throws \Nette\Utils\AssertionException
88
   * @throws InvalidMessageProcessorException
89
   */
90
  protected function getMessageProcessors(): array {
91 1
    $messageProcessors = [];
92 1
    $config = $this->getConfig($this->defaults);
93 1
    Validators::assertField($config, "messageProcessors", "array");
94 1
    foreach($config["messageProcessors"] as $name => $processor) {
95 1
      if(!class_exists($processor) OR !is_subclass_of($processor, IChatMessageProcessor::class)) {
96 1
        throw new InvalidMessageProcessorException("Invalid message processor $processor.");
97
      }
98 1
      $messageProcessors[$name] = $processor;
99
    }
100 1
    return $messageProcessors;
101
  }
102
  
103
  /**
104
   * @throws \Nette\Utils\AssertionException
105
   * @throws InvalidDatabaseAdapterException
106
   */
107
  protected function getDatabaseAdapter(): string {
108 1
    $config = $this->getConfig($this->defaults);
109 1
    Validators::assertField($config, "databaseAdapter", "string");
110 1
    $adapter = $config["databaseAdapter"];
111 1
    if(!class_exists($adapter) OR !is_subclass_of($adapter, IDatabaseAdapter::class)) {
112 1
      throw new InvalidDatabaseAdapterException("Invalid database adapter $adapter.");
113
    }
114 1
    return $adapter;
115
  }
116
  
117
  /**
118
   * @throws \Nette\Utils\AssertionException
119
   * @throws InvalidChatControlFactoryException
120
   * @throws InvalidMessageProcessorException
121
   * @throws InvalidDatabaseAdapterException
122
   */
123
  public function loadConfiguration(): void {
124 1
    $builder = $this->getContainerBuilder();
125 1
    $chats = $this->getChats();
126 1
    $characterProfileLink = $this->getCharacterProfileLink();
127 1
    foreach($chats as $name => $interface) {
128 1
      $chat = $builder->addDefinition($this->prefix($name))
129 1
        ->setImplement($interface)
130 1
        ->addTag(static::TAG_CHAT);
131 1
      if($characterProfileLink !== "") {
132 1
        $chat->addSetup("setCharacterProfileLink", [$characterProfileLink]);
133
      }
134
    }
135 1
    $messageProcessors = $this->getMessageProcessors();
136 1
    foreach($messageProcessors as $name => $processor) {
137 1
      $builder->addDefinition($this->prefix($name))
138 1
        ->setType($processor);
139
    }
140 1
    $databaseAdapter = $this->getDatabaseAdapter();
141 1
    $builder->addDefinition($this->prefix(static::SERVICE_DATABASE_ADAPTER))
142 1
      ->setType($databaseAdapter);
143 1
  }
144
  
145
  protected function registerMessageProcessors(): void {
146 1
    $builder = $this->getContainerBuilder();
147 1
    $chats = $this->getChats();
148 1
    $messageProcessors = $this->getMessageProcessors();
149 1
    foreach($chats as $chat => $chatClass) {
150 1
      $chatService = $builder->getDefinition($this->prefix($chat));
151 1
      foreach($messageProcessors as $processor => $processorClass) {
152 1
        $processorService = $builder->getDefinition($this->prefix($processor));
153 1
        $chatService->addSetup("addMessageProcessor", [$processorService]);
154
      }
155
    }
156 1
  }
157
  
158
  protected function registerChatCommands(): void {
159 1
    $builder = $this->getContainerBuilder();
160
    try {
161 1
      $processor = $builder->getDefinition($this->prefix(static::SERVICE_CHAT_COMMANDS_PROCESSOR));
162
    } catch(MissingServiceException $e) {
163
      return;
164
    }
165 1
    $chatCommands = $builder->findByType(IChatCommand::class);
166 1
    foreach($chatCommands as $command) {
167
      $processor->addSetup("addCommand", [$command]);
168
    }
169 1
  }
170
  
171
  public function beforeCompile(): void {
172 1
    $this->registerMessageProcessors();
173 1
    $this->registerChatCommands();
174 1
  }
175
}
176
?>