Passed
Push — master ( bb74df...01777c )
by Jakub
02:24
created

src/Bridges/NetteDI/TranslationExtension.php (2 issues)

Checks opening function brace kernighan ritchie space after bracket

Coding Style Informational

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
declare(strict_types=1);
3
4
namespace Nexendrie\Translation\Bridges\NetteDI;
5
6
use Nette\DI\CompilerExtension,
7
    Nette\PhpGenerator\ClassType,
8
    Nette\Utils\Validators,
9
    Nexendrie\Translation\Resolvers\ILocaleResolver,
10
    Nexendrie\Translation\Bridges\NetteApplication\IAppRequestAwareLocaleResolver,
11
    Nexendrie\Translation\Resolvers\EnvironmentLocaleResolver,
12
    Nexendrie\Translation\Resolvers\ManualLocaleResolver,
13
    Nexendrie\Translation\Resolvers\FallbackLocaleResolver,
14
    Nexendrie\Translation\Resolvers\ChainLocaleResolver,
15
    Nexendrie\Translation\Resolvers\SessionLocaleResolver,
16
    Nexendrie\Translation\Resolvers\HeaderLocaleResolver,
17
    Nexendrie\Translation\Bridges\NetteApplication\ParamLocaleResolver,
18
    Nexendrie\Translation\Translator,
19
    Nexendrie\Translation\Loaders\ILoader,
20
    Nexendrie\Translation\Loaders\FileLoader,
21
    Nexendrie\Translation\Loaders\NeonLoader,
22
    Nexendrie\Translation\Loaders\IniLoader,
23
    Nexendrie\Translation\Loaders\JsonLoader,
24
    Nexendrie\Translation\Loaders\YamlLoader,
25
    Nexendrie\Translation\Loaders\PhpLoader,
26
    Nexendrie\Translation\Loaders\MessagesCatalogue,
27
    Nexendrie\Translation\InvalidLocaleResolverException,
28
    Nexendrie\Translation\InvalidFolderException,
29
    Nexendrie\Translation\InvalidLoaderException,
30
    Nexendrie\Translation\Bridges\Tracy\TranslationPanel,
31
    Nexendrie\Translation\CatalogueCompiler,
32
    Nette\Utils\Arrays,
33
    Nette\Application\Application,
34
    Nette\Bridges\ApplicationLatte\ILatteFactory,
35
    Nette\Utils\AssertionException,
36
    Nexendrie\Translation\Resolvers\ILoaderAwareLocaleResolver;
37
38
/**
39
 * TranslationExtension for Nette DI Container
40
 *
41
 * @author Jakub Konečný
42
 */
43 1
class TranslationExtension extends CompilerExtension {
44
  /** @internal */
45
  const SERVICE_TRANSLATOR = "translator";
46
  /** @internal */
47
  const SERVICE_LOADER = "loader";
48
  /** @internal */
49
  const SERVICE_LOCALE_RESOLVER = "localeResolver";
50
  /** @internal */
51
  const SERVICE_PANEL = "panel";
52
  /** @internal */
53
  const SERVICE_CATALOGUE_COMPILER = "catalogueCompiler";
54
  /** @internal */
55
  const SERVICE_ORIGINAL_LOADER = "originalLoader";
56
  
57
  /** @var array */
58
  protected $defaults = [
59
    "localeResolver" => [
60
      "param", "session", "header",
61
    ],
62
    "default" => "en",
63
    "debugger" => "%debugMode%",
64
    "loader" => [
65
      "name" => "neon",
66
      "folders" => [
67
        "%appDir%/lang",
68
      ],
69
    ],
70
    "onUntranslated" => [],
71
    "compiler" => [
72
      "enabled" => false,
73
      "languages" => [],
74
    ],
75
  ];
76
  
77
  /** @var string[] */
78
  protected $resolvers = [
79
    "environment" => EnvironmentLocaleResolver::class,
80
    "manual" => ManualLocaleResolver::class,
81
    "fallback" => FallbackLocaleResolver::class,
82
    "session" => SessionLocaleResolver::class,
83
    "header" => HeaderLocaleResolver::class,
84
    "param" => ParamLocaleResolver::class
85
  ];
86
  
87
  /** @var string[] */
88
  protected $loaders = [
89
    "neon" => NeonLoader::class,
90
    "ini" => IniLoader::class,
91
    "json" => JsonLoader::class,
92
    "yaml" => YamlLoader::class,
93
    "php" => PhpLoader::class,
94
    "catalogue" => MessagesCatalogue::class,
95
  ];
96
  
97
  /**
98
   * @return string[]
99
   * @throws AssertionException
100
   * @throws InvalidLocaleResolverException
101
   */
102
  protected function resolveResolverClass(): array {
103 1
    $config = $this->getConfig($this->defaults);
104 1
    Validators::assertField($config, "localeResolver", "string|string[]");
105 1
    $return = [];
106 1
    $resolvers = $config["localeResolver"];
107 1
    if(!is_array($resolvers)) {
108 1
      $resolvers = [$resolvers];
109
    }
110 1
    foreach($resolvers as $resolverName) {
111 1
      $resolver = Arrays::get($this->resolvers, strtolower($resolverName), "");
112 1
      if($resolver !== "") {
113 1
        $return[] = $resolver;
114 1
      } elseif(class_exists($resolverName) AND is_subclass_of($resolverName, ILocaleResolver::class)) {
115 1
        $return[] = $resolverName;
116
      } else {
117 1
        throw new InvalidLocaleResolverException("Invalid locale resolver $resolverName.");
118
      }
119
    }
120 1
    return $return;
121
  }
122
  
123
  /**
124
   * @throws AssertionException
125
   * @throws InvalidLoaderException
126
   */
127
  protected function resolveLoaderClass(): string {
128 1
    $config = $this->getConfig($this->defaults);
129 1
    Validators::assertField($config, "loader", "array");
130 1
    Validators::assertField($config["loader"], "name", "string");
131 1
    $loaderName = $config["loader"]["name"];
132 1
    $loader = Arrays::get($this->loaders, strtolower($loaderName), "");
133 1
    if($loader !== "") {
134 1
      return $loader;
135 1
    } elseif(class_exists($loaderName) AND is_subclass_of($loaderName, ILoader::class)) {
136 1
      return $loaderName;
137
    }
138 1
    throw new InvalidLoaderException("Invalid translation loader.");
139
  }
140
  
141
  /**
142
   * @return string[]
143
   * @throws InvalidFolderException
144
   */
145
  protected function getFolders(): array {
146 1
    $config = $this->getConfig($this->defaults);
147 1
    Validators::assertField($config["loader"], "folders", "string[]");
148 1
    $folders = $config["loader"]["folders"];
149
    /** @var ITranslationProvider $extension */
150 1
    foreach($this->compiler->getExtensions(ITranslationProvider::class) as $extension) {
151 1
      $folders = array_merge($folders, array_values($extension->getTranslationResources()));
152
    }
153 1
    foreach($folders as $folder) {
154 1
      if(!is_dir($folder)) {
155 1
        throw new InvalidFolderException("Folder $folder does not exist.");
156
      }
157
    }
158 1
    return $folders;
159
  }
160
  
161
  /**
162
   * @throws AssertionException
163
   * @throws InvalidLocaleResolverException
164
   * @throws InvalidLoaderException
165
   */
166
  function loadConfiguration(): void {
0 ignored issues
show
Expected 1 space after closing parenthesis; found 0
Loading history...
167 1
    $this->defaults["onUntranslated"][] = ["@" . $this->prefix(static::SERVICE_TRANSLATOR), "logUntranslatedMessage"];
168 1
    $builder = $this->getContainerBuilder();
169 1
    $config = $this->getConfig($this->defaults);
170 1
    Validators::assertField($config, "default", "string");
171 1
    Validators::assertField($config["compiler"], "enabled", "bool");
172 1
    Validators::assertField($config["compiler"], "languages", "string[]");
173 1
    $resolvers = $this->resolveResolverClass();
174 1
    $loader = $this->resolveLoaderClass();
175 1
    $builder->addDefinition($this->prefix(static::SERVICE_TRANSLATOR))
176 1
      ->setClass(Translator::class);
177 1
    $builder->addDefinition($this->prefix(static::SERVICE_LOADER))
178 1
      ->setClass($loader)
179 1
      ->addSetup("setDefaultLang", [$config["default"]]);
180 1
    if(count($resolvers) === 1) {
181 1
      $builder->addDefinition($this->prefix(static::SERVICE_LOCALE_RESOLVER))
182 1
        ->setClass($resolvers[0]);
183
    } else {
184 1
      $chainResolver = $builder->addDefinition($this->prefix(static::SERVICE_LOCALE_RESOLVER))
185 1
        ->setClass(ChainLocaleResolver::class);
186 1
      foreach($resolvers as $index => $resolver) {
187 1
        $resolverService = $builder->addDefinition($this->prefix("resolver.$index"))
188 1
          ->setClass($resolver)
189 1
          ->setAutowired(false);
190 1
        $chainResolver->addSetup("addResolver", [$resolverService]);
191
      }
192
    }
193 1
    if($config["debugger"] AND interface_exists(\Tracy\IBarPanel::class)) {
194 1
      $builder->addDefinition($this->prefix(static::SERVICE_PANEL))
195 1
        ->setClass(TranslationPanel::class);
196 1
      $builder->getDefinition("tracy.bar")
197 1
        ->addSetup("addPanel", ["@" . $this->prefix(static::SERVICE_PANEL), "translation"]);
198
    }
199 1
  }
200
  
201
  /**
202
   * @throws InvalidFolderException
203
   */
204
  function beforeCompile(): void {
0 ignored issues
show
Expected 1 space after closing parenthesis; found 0
Loading history...
205 1
    $builder = $this->getContainerBuilder();
206 1
    $config = $this->getConfig($this->defaults);
207 1
    $loader = $builder->getDefinition($this->prefix(static::SERVICE_LOADER));
208 1
    if(in_array(FileLoader::class, class_parents($loader->class))) {
209 1
      $folders = $this->getFolders();
210 1
      $loader->addSetup("setFolders", [$folders]);
211 1
      foreach($folders as $folder) {
212 1
        $builder->addDependency($folder);
213
      }
214
    }
215 1
    $resolver = $builder->getDefinition($this->prefix(static::SERVICE_LOCALE_RESOLVER));
216 1
    if(in_array(IAppRequestAwareLocaleResolver::class, class_implements($resolver->class))) {
217 1
      $applicationService = $builder->getByType(Application::class) ?? "application";
218 1
      if($builder->hasDefinition($applicationService)) {
219 1
        $builder->getDefinition($applicationService)
220 1
          ->addSetup('$service->onRequest[] = ?', [[$resolver, "onRequest"]]);
221
      }
222
    }
223 1
    if($config["compiler"]["enabled"]) {
224 1
      $serviceName = $this->prefix(static::SERVICE_LOADER);
225 1
      $loader = $builder->getDefinition($serviceName);
226 1
      $builder->removeDefinition($serviceName);
227 1
      $folder = $builder->expand("%tempDir%/catalogues");
228 1
      $builder->addDefinition($this->prefix(static::SERVICE_ORIGINAL_LOADER), $loader)
229 1
        ->setFactory($loader->class, [new ManualLocaleResolver, $config["loader"]["folders"]])
230 1
        ->setAutowired(false);
231 1
      $builder->addDefinition($serviceName)
232 1
        ->setClass(MessagesCatalogue::class)
233 1
        ->addSetup("setFolders", [[$folder]]);
234 1
      $builder->addDefinition($this->prefix(static::SERVICE_CATALOGUE_COMPILER))
235 1
        ->setFactory(CatalogueCompiler::class, [$loader, $folder, $config["compiler"]["languages"]]);
236
    }
237 1
    $latteFactoryService = $builder->getByType(ILatteFactory::class) ?? "latte.latteFactory";
238 1
    if($builder->hasDefinition($latteFactoryService)) {
239 1
      $latteFactory = $builder->getDefinition($latteFactoryService);
240 1
      $latteFactory->addSetup("addFilter", ["translate", ["@" . $this->prefix(static::SERVICE_TRANSLATOR), "translate"]]);
241 1
      $latteFactory->addSetup("addProvider", ["translator", "@" . $this->prefix(static::SERVICE_TRANSLATOR)]);
242
    }
243 1
  }
244
  
245
  function afterCompile(ClassType $class): void {
246 1
    $config = $this->getConfig($this->defaults);
247 1
    $initialize = $class->methods["initialize"];
248 1
    $initialize->addBody('$translator = $this->getService(?);', [$this->prefix(static::SERVICE_TRANSLATOR)]);
249 1
    foreach($config["onUntranslated"] as &$task) {
250 1
      if(!is_array($task)) {
251 1
        $task = explode("::", $task);
252 1
      } elseif(substr($task[0], 0, 1) === "@") {
253 1
        $initialize->addBody('$translator->onUntranslated[] = [$this->getService(?), ?];', [substr($task[0], 1), $task[1]]);
254 1
        continue;
255
      }
256 1
      $initialize->addBody('$translator->onUntranslated[] = [?, ?];', [$task[0], $task[1]]);
257
    }
258 1
    $initialize->addBody('$resolvers = $this->findByType(?);
259 1
foreach($resolvers as $resolver) $this->getService($resolver)->setLoader($this->getService(?));', [ILoaderAwareLocaleResolver::class, $this->prefix(static::SERVICE_LOADER)]);
260 1
    if($config["compiler"]["enabled"]) {
261 1
      $initialize->addBody('$this->getService(?)->compile();', [$this->prefix(static::SERVICE_CATALOGUE_COMPILER)]);
262
    }
263 1
  }
264
}
265
?>