Completed
Push — master ( 63f783...d7278c )
by Jakub
08:07
created

ChatExtension::getConfigSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 1
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 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\ServiceDefinition;
19
20
/**
21
 * ChatExtension
22
 *
23
 * @author Jakub Konečný
24
 */
25 1
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
35
  public function getConfigSchema(): \Nette\Schema\Schema {
36 1
    return Expect::structure([
37 1
      "chats" => Expect::arrayOf("interface")->default([])->required(),
38 1
      "messageProcessors" => Expect::arrayOf("class")->default([
39 1
        self::SERVICE_CHAT_COMMANDS_PROCESSOR => ChatCommandsProcessor::class,
40
        ]),
41 1
      "databaseAdapter" => Expect::type("class")->required(),
42 1
      "characterProfileLink" => Expect::string(""),
43
    ]);
44
  }
45
46
  /**
47
   * @throws InvalidChatControlFactoryException
48
   */
49
  protected function validateFactory(string $interface): void {
50
    try {
51 1
      $rm = new \ReflectionMethod($interface, "create");
52 1
    } catch(\ReflectionException $e) {
53 1
      throw new InvalidChatControlFactoryException("Interface $interface does not contain method create.", 0, $e);
54
    }
55 1
    $returnType = $rm->getReturnType();
56 1
    if(is_null($returnType) OR !is_subclass_of($returnType->getName(), ChatControl::class)) {
57 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...
58
    }
59 1
  }
60
  
61
  /**
62
   * @throws InvalidChatControlFactoryException
63
   */
64
  protected function getChats(): array {
65 1
    $chats = [];
66
    /** @var \stdClass $config */
67 1
    $config = $this->getConfig();
68 1
    foreach($config->chats as $name => $interface) {
69 1
      $this->validateFactory($interface);
70 1
      $chats[$name] = $interface;
71
    }
72 1
    return $chats;
73
  }
74
75
  protected function getCharacterProfileLink(): string {
76
    /** @var \stdClass $config */
77 1
    $config = $this->getConfig();
78 1
    return $config->characterProfileLink;
79
  }
80
  
81
  /**
82
   * @throws InvalidMessageProcessorException
83
   */
84
  protected function getMessageProcessors(): array {
85 1
    $messageProcessors = [];
86
    /** @var \stdClass $config */
87 1
    $config = $this->getConfig();
88 1
    foreach($config->messageProcessors as $name => $processor) {
89 1
      if(!class_exists($processor) OR !is_subclass_of($processor, IChatMessageProcessor::class)) {
90 1
        throw new InvalidMessageProcessorException("Invalid message processor $processor.");
91
      }
92 1
      $messageProcessors[$name] = $processor;
93
    }
94 1
    return $messageProcessors;
95
  }
96
  
97
  /**
98
   * @throws InvalidDatabaseAdapterException
99
   */
100
  protected function getDatabaseAdapter(): string {
101
    /** @var \stdClass $config */
102 1
    $config = $this->getConfig();
103 1
    $adapter = $config->databaseAdapter;
104 1
    if(!class_exists($adapter) OR !is_subclass_of($adapter, IDatabaseAdapter::class)) {
105 1
      throw new InvalidDatabaseAdapterException("Invalid database adapter $adapter.");
106
    }
107 1
    return $adapter;
108
  }
109
  
110
  /**
111
   * @throws InvalidChatControlFactoryException
112
   * @throws InvalidMessageProcessorException
113
   * @throws InvalidDatabaseAdapterException
114
   */
115
  public function loadConfiguration(): void {
116 1
    $builder = $this->getContainerBuilder();
117 1
    $chats = $this->getChats();
118 1
    $characterProfileLink = $this->getCharacterProfileLink();
119 1
    foreach($chats as $name => $interface) {
120 1
      $chat = $builder->addFactoryDefinition($this->prefix($name))
121 1
        ->setImplement($interface)
122 1
        ->addTag(static::TAG_CHAT);
123 1
      if($characterProfileLink !== "") {
124 1
        $chat->getResultDefinition()->addSetup("setCharacterProfileLink", [$characterProfileLink]);
125
      }
126
    }
127 1
    $messageProcessors = $this->getMessageProcessors();
128 1
    foreach($messageProcessors as $name => $processor) {
129 1
      $builder->addDefinition($this->prefix($name))
130 1
        ->setType($processor);
131
    }
132 1
    $databaseAdapter = $this->getDatabaseAdapter();
133 1
    $builder->addDefinition($this->prefix(static::SERVICE_DATABASE_ADAPTER))
134 1
      ->setType($databaseAdapter);
135 1
    $builder->addDefinition($this->prefix(static::SERVICE_NEW_MESSAGE_FORM))
136 1
      ->setType(NewChatMessageFormFactory::class);
137 1
  }
138
  
139
  protected function registerMessageProcessors(): void {
140 1
    $builder = $this->getContainerBuilder();
141 1
    $chats = $this->getChats();
142 1
    $messageProcessors = $this->getMessageProcessors();
143 1
    foreach($chats as $chat => $chatClass) {
144
      /** @var FactoryDefinition $chatService */
145 1
      $chatService = $builder->getDefinition($this->prefix($chat));
146 1
      foreach($messageProcessors as $processor => $processorClass) {
147 1
        $processorService = $builder->getDefinition($this->prefix($processor));
148 1
        $chatService->getResultDefinition()->addSetup("addMessageProcessor", [$processorService]);
149
      }
150
    }
151 1
  }
152
  
153
  protected function registerChatCommands(): void {
154 1
    $builder = $this->getContainerBuilder();
155
    try {
156
      /** @var ServiceDefinition $processor */
157 1
      $processor = $builder->getDefinition($this->prefix(static::SERVICE_CHAT_COMMANDS_PROCESSOR));
158
    } catch(MissingServiceException $e) {
159
      return;
160
    }
161 1
    $chatCommands = $builder->findByType(IChatCommand::class);
162 1
    foreach($chatCommands as $command) {
163
      $processor->addSetup("addCommand", [$command]);
164
    }
165 1
  }
166
  
167
  public function beforeCompile(): void {
168 1
    $this->registerMessageProcessors();
169 1
    $this->registerChatCommands();
170 1
  }
171
}
172
?>