Passed
Pull Request — master (#5)
by Radovan
02:05
created
src/TranslatorProvider.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -21,53 +21,53 @@
 block discarded – undo
21 21
 
22 22
 class TranslatorProvider
23 23
 {
24
-	/**
25
-	 * @var array<string, CatalogueBuilder>
26
-	 */
27
-	protected array $catalogues = [];
24
+    /**
25
+     * @var array<string, CatalogueBuilder>
26
+     */
27
+    protected array $catalogues = [];
28 28
 
29
-	/**
30
-	 * @var array<string, Interfaces\Translator>
31
-	 */
32
-	protected array $translators = [];
29
+    /**
30
+     * @var array<string, Interfaces\Translator>
31
+     */
32
+    protected array $translators = [];
33 33
 
34
-	/**
35
-	 * @param array<string> $languages
36
-	 */
37
-	public function __construct(
38
-		protected array $languages,
39
-		protected ?Interfaces\Diagnostics $diagnostics = null
40
-	) {}
34
+    /**
35
+     * @param array<string> $languages
36
+     */
37
+    public function __construct(
38
+        protected array $languages,
39
+        protected ?Interfaces\Diagnostics $diagnostics = null
40
+    ) {}
41 41
 
42
-	public function addCatalogue(
43
-		string $locale,
44
-		CatalogueBuilder $builder
45
-	): void {
46
-		$this->catalogues[strtolower($locale)] = $builder;
47
-	}
42
+    public function addCatalogue(
43
+        string $locale,
44
+        CatalogueBuilder $builder
45
+    ): void {
46
+        $this->catalogues[strtolower($locale)] = $builder;
47
+    }
48 48
 
49
-	public function getTranslator(string $locale): Interfaces\Translator
50
-	{
51
-		$locale = strtolower($locale);
52
-		if (!isset($this->translators[$locale])) {
53
-			$this->translators[$locale] = $this->createTranslator($locale);
54
-		}
49
+    public function getTranslator(string $locale): Interfaces\Translator
50
+    {
51
+        $locale = strtolower($locale);
52
+        if (!isset($this->translators[$locale])) {
53
+            $this->translators[$locale] = $this->createTranslator($locale);
54
+        }
55 55
 
56
-		return $this->translators[$locale];
57
-	}
56
+        return $this->translators[$locale];
57
+    }
58 58
 
59
-	/**
60
-	 * @throws BuilderException
61
-	 */
62
-	protected function createTranslator(string $locale): Interfaces\Translator
63
-	{
64
-		if (!isset($this->catalogues[$locale])) {
65
-			throw new TranslatorException("Language {$locale} requested, but corresponding catalogue missing.");
66
-		}
59
+    /**
60
+     * @throws BuilderException
61
+     */
62
+    protected function createTranslator(string $locale): Interfaces\Translator
63
+    {
64
+        if (!isset($this->catalogues[$locale])) {
65
+            throw new TranslatorException("Language {$locale} requested, but corresponding catalogue missing.");
66
+        }
67 67
 
68
-		return new Translator(
69
-			$this->catalogues[$locale]->compile(),
70
-			$this->diagnostics
71
-		);
72
-	}
68
+        return new Translator(
69
+            $this->catalogues[$locale]->compile(),
70
+            $this->diagnostics
71
+        );
72
+    }
73 73
 }
Please login to merge, or discard this patch.
src/Diagnostics/Diagnostics.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -20,48 +20,48 @@
 block discarded – undo
20 20
 
21 21
 class Diagnostics implements Interfaces\Diagnostics
22 22
 {
23
-	/** @var string */
24
-	private string $locale = '';
23
+    /** @var string */
24
+    private string $locale = '';
25 25
 
26
-	/** @var array<string> */
27
-	private array $messages = [];
26
+    /** @var array<string> */
27
+    private array $messages = [];
28 28
 
29
-	/** @var array<string> */
30
-	private array $untranslated = [];
29
+    /** @var array<string> */
30
+    private array $untranslated = [];
31 31
 
32
-	public function getLocale(): string
33
-	{
34
-		return $this->locale;
35
-	}
32
+    public function getLocale(): string
33
+    {
34
+        return $this->locale;
35
+    }
36 36
 
37
-	/**
38
-	 * @return string[]
39
-	 */
40
-	public function getUntranslated(): array
41
-	{
42
-		return array_unique($this->untranslated);
43
-	}
37
+    /**
38
+     * @return string[]
39
+     */
40
+    public function getUntranslated(): array
41
+    {
42
+        return array_unique($this->untranslated);
43
+    }
44 44
 
45
-	/**
46
-	 * @return string[]
47
-	 */
48
-	public function getWarnings(): array
49
-	{
50
-		return array_unique($this->messages);
51
-	}
45
+    /**
46
+     * @return string[]
47
+     */
48
+    public function getWarnings(): array
49
+    {
50
+        return array_unique($this->messages);
51
+    }
52 52
 
53
-	public function setLocale(string $locale): void
54
-	{
55
-		$this->locale = $locale;
56
-	}
53
+    public function setLocale(string $locale): void
54
+    {
55
+        $this->locale = $locale;
56
+    }
57 57
 
58
-	public function untranslated(string $message): void
59
-	{
60
-		$this->untranslated[] = $message;
61
-	}
58
+    public function untranslated(string $message): void
59
+    {
60
+        $this->untranslated[] = $message;
61
+    }
62 62
 
63
-	public function warning(string $message): void
64
-	{
65
-		$this->messages[] = $message;
66
-	}
63
+    public function warning(string $message): void
64
+    {
65
+        $this->messages[] = $message;
66
+    }
67 67
 }
Please login to merge, or discard this patch.
src/Interfaces/Diagnostics.php 1 patch
Indentation   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -16,7 +16,7 @@
 block discarded – undo
16 16
 
17 17
 interface Diagnostics
18 18
 {
19
-	public function setLocale(string $locale): void;
20
-	public function untranslated(string $message): void;
21
-	public function warning(string $message): void;
19
+    public function setLocale(string $locale): void;
20
+    public function untranslated(string $message): void;
21
+    public function warning(string $message): void;
22 22
 }
Please login to merge, or discard this patch.
src/Interfaces/Translator.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -23,10 +23,10 @@
 block discarded – undo
23 23
  */
24 24
 interface Translator
25 25
 {
26
-	/**
27
-	 * @param callable $callback function(string $string): string
28
-	 */
29
-	public function setNormalizeCallback(callable $callback): void;
26
+    /**
27
+     * @param callable $callback function(string $string): string
28
+     */
29
+    public function setNormalizeCallback(callable $callback): void;
30 30
 
31
-	public function translate(string|Stringable $message, mixed ...$params): string;
31
+    public function translate(string|Stringable $message, mixed ...$params): string;
32 32
 }
Please login to merge, or discard this patch.
src/PluralProvider.php 1 patch
Indentation   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -20,47 +20,47 @@
 block discarded – undo
20 20
 
21 21
 final class PluralProvider
22 22
 {
23
-	/**
24
-	 * Czech plural selector (zero-one-few-other)
25
-	 */
26
-	public static function csPlural(?int $n): Plural
27
-	{
28
-		return match (true) {
29
-			$n === 0 => Plural::Zero,
30
-			$n === 1 => Plural::One,
31
-			$n >= 2 && $n <= 4 => Plural::Few,
32
-			default => Plural::Other,
33
-		};
34
-	}
23
+    /**
24
+     * Czech plural selector (zero-one-few-other)
25
+     */
26
+    public static function csPlural(?int $n): Plural
27
+    {
28
+        return match (true) {
29
+            $n === 0 => Plural::Zero,
30
+            $n === 1 => Plural::One,
31
+            $n >= 2 && $n <= 4 => Plural::Few,
32
+            default => Plural::Other,
33
+        };
34
+    }
35 35
 
36
-	/**
37
-	 * Default plural detector (zero-one-other)
38
-	 */
39
-	public static function enPlural(?int $n): Plural
40
-	{
41
-		return match (true) {
42
-			$n === 0 => Plural::Zero,
43
-			$n === 1 => Plural::One,
44
-			default => Plural::Other,
45
-		};
46
-	}
36
+    /**
37
+     * Default plural detector (zero-one-other)
38
+     */
39
+    public static function enPlural(?int $n): Plural
40
+    {
41
+        return match (true) {
42
+            $n === 0 => Plural::Zero,
43
+            $n === 1 => Plural::One,
44
+            default => Plural::Other,
45
+        };
46
+    }
47 47
 
48
-	/**
49
-	 * No plural detector (zero-other)
50
-	 */
51
-	public static function zeroPlural(?int $n): Plural
52
-	{
53
-		return $n === 0
54
-			? Plural::Zero
55
-			: Plural::Other;
56
-	}
48
+    /**
49
+     * No plural detector (zero-other)
50
+     */
51
+    public static function zeroPlural(?int $n): Plural
52
+    {
53
+        return $n === 0
54
+            ? Plural::Zero
55
+            : Plural::Other;
56
+    }
57 57
 
58
-	public function getPlural(string $locale): callable
59
-	{
60
-		return match (strtolower($locale)) {
61
-			'cs' => [$this, 'csPlural'],
62
-			'id', 'ja', 'ka', 'ko', 'lo', 'ms', 'my', 'th', 'vi', 'zh' => [$this, 'zeroPlural'],
63
-			default => [$this, 'enPlural'],
64
-		};
65
-	}
58
+    public function getPlural(string $locale): callable
59
+    {
60
+        return match (strtolower($locale)) {
61
+            'cs' => [$this, 'csPlural'],
62
+            'id', 'ja', 'ka', 'ko', 'lo', 'ms', 'my', 'th', 'vi', 'zh' => [$this, 'zeroPlural'],
63
+            default => [$this, 'enPlural'],
64
+        };
65
+    }
66 66
 }
Please login to merge, or discard this patch.
src/Catalogue.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -21,23 +21,23 @@
 block discarded – undo
21 21
  */
22 22
 abstract class Catalogue
23 23
 {
24
-	/** @var array<string|array<string, string>> */
25
-	protected static array $messages;
24
+    /** @var array<string|array<string, string>> */
25
+    protected static array $messages;
26 26
 
27
-	/**
28
-	 * @return string|array<string, string>
29
-	 */
30
-	public function get(string $message): array|string
31
-	{
32
-		return static::$messages[$message] ?? '';
33
-	}
27
+    /**
28
+     * @return string|array<string, string>
29
+     */
30
+    public function get(string $message): array|string
31
+    {
32
+        return static::$messages[$message] ?? '';
33
+    }
34 34
 
35
-	public function has(string $message): bool
36
-	{
37
-		return array_key_exists($message, static::$messages);
38
-	}
35
+    public function has(string $message): bool
36
+    {
37
+        return array_key_exists($message, static::$messages);
38
+    }
39 39
 
40
-	abstract public function plural(int $n): Plural;
41
-	abstract public function locale(): string;
42
-	abstract public function build(): int;
40
+    abstract public function plural(int $n): Plural;
41
+    abstract public function locale(): string;
42
+    abstract public function build(): int;
43 43
 }
Please login to merge, or discard this patch.
src/Plural.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -6,10 +6,10 @@
 block discarded – undo
6 6
 
7 7
 enum Plural: string
8 8
 {
9
-	case Zero = 'zero';
10
-	case One = 'one';
11
-	case Two = 'two';
12
-	case Few = 'few';
13
-	case Many = 'many';
14
-	case Other = 'other';
9
+    case Zero = 'zero';
10
+    case One = 'one';
11
+    case Two = 'two';
12
+    case Few = 'few';
13
+    case Many = 'many';
14
+    case Other = 'other';
15 15
 }
Please login to merge, or discard this patch.
src/Translator.php 2 patches
Indentation   +92 added lines, -92 removed lines patch added patch discarded remove patch
@@ -29,96 +29,96 @@
 block discarded – undo
29 29
  */
30 30
 class Translator implements Interfaces\Translator
31 31
 {
32
-	/** @var callable function(string $string): string */
33
-	private $normalizeCallback;
34
-
35
-	public function __construct(
36
-		private readonly Catalogue $catalogue,
37
-		private readonly ?Diagnostics $diagnostics = null
38
-	) {
39
-		$this->normalizeCallback = [$this, 'normalize'];
40
-		$this->diagnostics?->setLocale($catalogue->locale());
41
-	}
42
-
43
-	public function normalize(string $string): string
44
-	{
45
-		return str_replace(
46
-			['%label', '%value', '%name'],
47
-			['%%label', '%%value', '%%name'],
48
-			$string
49
-		);
50
-	}
51
-
52
-	public function setNormalizeCallback(callable $callback): void
53
-	{
54
-		$this->normalizeCallback = $callback;
55
-	}
56
-
57
-	public function translate(string|Stringable $message, mixed ...$parameters): string
58
-	{
59
-		$message = (string) $message;
60
-
61
-		if (empty($message)) {
62
-			return '';
63
-		}
64
-
65
-		$translation = $this->catalogue->get($message);
66
-		if (!$translation) {
67
-			$this->untranslated($message);
68
-			return $message;
69
-		}
70
-
71
-		// Plural option is returned, we need to choose the right one
72
-		if (is_array($translation)) {
73
-			$plural = is_numeric($parameters[0] ?? null) ? $this->catalogue->plural((int) $parameters[0]) : Plural::Other;
74
-			$translation = $this->getVariant($message, $translation, $plural);
75
-		}
76
-
77
-		if (!empty($parameters)) {
78
-			$translation = ($this->normalizeCallback)($translation);
79
-			$translation = @vsprintf($translation, $parameters);
80
-		}
81
-
82
-		return $translation;
83
-	}
84
-
85
-	/**
86
-	 * @param array<string, string> $translations
87
-	 */
88
-	public function getVariant(string $message, array $translations, Plural $plural): string
89
-	{
90
-		if (!array_key_exists($plural->value, $translations)) {
91
-			$this->warn(
92
-				'Plural form not defined. (message: %s, form: %s)',
93
-				$message,
94
-				$plural->value,
95
-			);
96
-		}
97
-
98
-		return $translations[$plural->value] ?? $translations[array_key_last($translations)];
99
-	}
100
-
101
-	/**
102
-	 * @param string $message
103
-	 */
104
-	protected function untranslated(string $message): void
105
-	{
106
-		$this->diagnostics?->untranslated($message);
107
-	}
108
-
109
-	/**
110
-	 * @param string $message
111
-	 * @param mixed ...$parameters
112
-	 * @return string
113
-	 */
114
-	protected function warn(string $message, ...$parameters): string
115
-	{
116
-		if (!empty($parameters)) {
117
-			$message = @vsprintf($message, $parameters);
118
-		} // Intentionally @ as parameter count can mismatch
119
-
120
-		$this->diagnostics?->warning($message);
121
-
122
-		return $message;
123
-	}
32
+    /** @var callable function(string $string): string */
33
+    private $normalizeCallback;
34
+
35
+    public function __construct(
36
+        private readonly Catalogue $catalogue,
37
+        private readonly ?Diagnostics $diagnostics = null
38
+    ) {
39
+        $this->normalizeCallback = [$this, 'normalize'];
40
+        $this->diagnostics?->setLocale($catalogue->locale());
41
+    }
42
+
43
+    public function normalize(string $string): string
44
+    {
45
+        return str_replace(
46
+            ['%label', '%value', '%name'],
47
+            ['%%label', '%%value', '%%name'],
48
+            $string
49
+        );
50
+    }
51
+
52
+    public function setNormalizeCallback(callable $callback): void
53
+    {
54
+        $this->normalizeCallback = $callback;
55
+    }
56
+
57
+    public function translate(string|Stringable $message, mixed ...$parameters): string
58
+    {
59
+        $message = (string) $message;
60
+
61
+        if (empty($message)) {
62
+            return '';
63
+        }
64
+
65
+        $translation = $this->catalogue->get($message);
66
+        if (!$translation) {
67
+            $this->untranslated($message);
68
+            return $message;
69
+        }
70
+
71
+        // Plural option is returned, we need to choose the right one
72
+        if (is_array($translation)) {
73
+            $plural = is_numeric($parameters[0] ?? null) ? $this->catalogue->plural((int) $parameters[0]) : Plural::Other;
74
+            $translation = $this->getVariant($message, $translation, $plural);
75
+        }
76
+
77
+        if (!empty($parameters)) {
78
+            $translation = ($this->normalizeCallback)($translation);
79
+            $translation = @vsprintf($translation, $parameters);
80
+        }
81
+
82
+        return $translation;
83
+    }
84
+
85
+    /**
86
+     * @param array<string, string> $translations
87
+     */
88
+    public function getVariant(string $message, array $translations, Plural $plural): string
89
+    {
90
+        if (!array_key_exists($plural->value, $translations)) {
91
+            $this->warn(
92
+                'Plural form not defined. (message: %s, form: %s)',
93
+                $message,
94
+                $plural->value,
95
+            );
96
+        }
97
+
98
+        return $translations[$plural->value] ?? $translations[array_key_last($translations)];
99
+    }
100
+
101
+    /**
102
+     * @param string $message
103
+     */
104
+    protected function untranslated(string $message): void
105
+    {
106
+        $this->diagnostics?->untranslated($message);
107
+    }
108
+
109
+    /**
110
+     * @param string $message
111
+     * @param mixed ...$parameters
112
+     * @return string
113
+     */
114
+    protected function warn(string $message, ...$parameters): string
115
+    {
116
+        if (!empty($parameters)) {
117
+            $message = @vsprintf($message, $parameters);
118
+        } // Intentionally @ as parameter count can mismatch
119
+
120
+        $this->diagnostics?->warning($message);
121
+
122
+        return $message;
123
+    }
124 124
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -56,7 +56,7 @@  discard block
 block discarded – undo
56 56
 
57 57
 	public function translate(string|Stringable $message, mixed ...$parameters): string
58 58
 	{
59
-		$message = (string) $message;
59
+		$message = (string)$message;
60 60
 
61 61
 		if (empty($message)) {
62 62
 			return '';
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
 
71 71
 		// Plural option is returned, we need to choose the right one
72 72
 		if (is_array($translation)) {
73
-			$plural = is_numeric($parameters[0] ?? null) ? $this->catalogue->plural((int) $parameters[0]) : Plural::Other;
73
+			$plural = is_numeric($parameters[0] ?? null) ? $this->catalogue->plural((int)$parameters[0]) : Plural::Other;
74 74
 			$translation = $this->getVariant($message, $translation, $plural);
75 75
 		}
76 76
 
Please login to merge, or discard this patch.
src/CatalogueBuilder.php 2 patches
Indentation   +296 added lines, -296 removed lines patch added patch discarded remove patch
@@ -36,305 +36,305 @@
 block discarded – undo
36 36
 
37 37
 final class CatalogueBuilder
38 38
 {
39
-	/** @var callable[] */
40
-	public array $onCompile = [];
41
-
42
-	/** @var callable[] */
43
-	public array $onCheck = [];
44
-
45
-	/** @var callable[] */
46
-	private array $dynamic = [];
47
-
48
-	private ?Catalogue $catalogue = null;
49
-
50
-	/** @var array<string> */
51
-	private array $collection = [];
52
-
53
-	private bool $debug = false;
54
-	private bool $loaded = false;
55
-	private string $locale;
56
-
57
-
58
-	public function __construct(
59
-		private readonly PluralProvider $plural,
60
-		private readonly string $path,
61
-		string $locale
62
-	) {
63
-		if (!is_writable($path)) {
64
-			throw new PathInvalidException("Path '$path' is not writable.");
65
-		}
66
-
67
-		$this->locale = strtolower($locale);
68
-	}
69
-
70
-	public function addFile(string $file): self
71
-	{
72
-		$this->collection[] = $file;
73
-		return $this;
74
-	}
75
-
76
-	public function addDynamic(string $resource, callable $callback): self
77
-	{
78
-		$this->dynamic[strtolower($resource)] = $callback;
79
-		return $this;
80
-	}
81
-
82
-	/**
83
-	 * @throws Throwable
84
-	 */
85
-	public function rebuild(int $attempt = 0): Catalogue
86
-	{
87
-		$filename = $this->path . '/' . $this->getName() . '.php';
88
-		$this->unlink($filename);
89
-		return $this->compile($attempt);
90
-	}
91
-
92
-	/**
93
-	 * @return string
94
-	 */
95
-	protected function getName(): string
96
-	{
97
-		return $this->locale . 'Catalogue';
98
-	}
99
-
100
-	/**
101
-	 * @param string $filename
102
-	 */
103
-	private function unlink(string $filename): void
104
-	{
105
-		/** @scrutinizer ignore-unhandled */
106
-		@unlink($filename); // @ intentionally as file may not exist
107
-		$this->loaded = false;
108
-	}
109
-
110
-	/**
111
-	 * @throws BuilderException
112
-	 */
113
-	public function compile(int $rebuild = 0): Catalogue
114
-	{
115
-		// Exception on to many rebuild try
116
-		if ($rebuild > 3) {
117
-			throw new BuilderException('Failed to build language file');
118
-		}
119
-
120
-		// Check for file exist, create if no
121
-		$filename = $this->path . '/' . $this->getName() . '.php';
122
-		if (!file_exists($filename)) {
123
-			file_put_contents($filename, $this->compileCode());
124
-		}
125
-
126
-		// Link file and rebuild if error
127
-		try {
128
-			$this->checkForChanges($filename);
129
-			$this->link($filename);
130
-
131
-			if (!$this->catalogue instanceof Catalogue) {
132
-				throw new BuilderException('Catalogue is not implementing Catalogue');
133
-			}
134
-
135
-			return $this->catalogue;
136
-		} catch (Throwable $e) {
137
-			$this->unlink($filename);
138
-			return $this->compile(++$rebuild);
139
-		}
140
-	}
141
-
142
-	/**
143
-	 * @param string $filename
144
-	 */
145
-	protected function checkForChanges(string $filename): void
146
-	{
147
-		if (!$this->debug) {
148
-			return;
149
-		}
150
-
151
-		$cacheTime = (int) filemtime($filename);
152
-		foreach ($this->collection as $file) {
153
-			$file = new SplFileInfo($file);
154
-			$fileTime = $file->getMTime();
155
-			if ($fileTime > $cacheTime || ($this->catalogue && $fileTime > $this->catalogue->build())) {
156
-				throw new BuilderException('Rebuild required');
157
-			}
158
-		}
159
-
160
-		$this->onCheck($cacheTime);
161
-	}
162
-
163
-	/**
164
-	 * Compile cache code
165
-	 *
166
-	 * @return string
167
-	 */
168
-	protected function compileCode(): string
169
-	{
170
-		// Load messages, then generate code
171
-		$messages = $this->getMessages();
172
-		$this->onCompile($messages);
173
-
174
-		/*
39
+    /** @var callable[] */
40
+    public array $onCompile = [];
41
+
42
+    /** @var callable[] */
43
+    public array $onCheck = [];
44
+
45
+    /** @var callable[] */
46
+    private array $dynamic = [];
47
+
48
+    private ?Catalogue $catalogue = null;
49
+
50
+    /** @var array<string> */
51
+    private array $collection = [];
52
+
53
+    private bool $debug = false;
54
+    private bool $loaded = false;
55
+    private string $locale;
56
+
57
+
58
+    public function __construct(
59
+        private readonly PluralProvider $plural,
60
+        private readonly string $path,
61
+        string $locale
62
+    ) {
63
+        if (!is_writable($path)) {
64
+            throw new PathInvalidException("Path '$path' is not writable.");
65
+        }
66
+
67
+        $this->locale = strtolower($locale);
68
+    }
69
+
70
+    public function addFile(string $file): self
71
+    {
72
+        $this->collection[] = $file;
73
+        return $this;
74
+    }
75
+
76
+    public function addDynamic(string $resource, callable $callback): self
77
+    {
78
+        $this->dynamic[strtolower($resource)] = $callback;
79
+        return $this;
80
+    }
81
+
82
+    /**
83
+     * @throws Throwable
84
+     */
85
+    public function rebuild(int $attempt = 0): Catalogue
86
+    {
87
+        $filename = $this->path . '/' . $this->getName() . '.php';
88
+        $this->unlink($filename);
89
+        return $this->compile($attempt);
90
+    }
91
+
92
+    /**
93
+     * @return string
94
+     */
95
+    protected function getName(): string
96
+    {
97
+        return $this->locale . 'Catalogue';
98
+    }
99
+
100
+    /**
101
+     * @param string $filename
102
+     */
103
+    private function unlink(string $filename): void
104
+    {
105
+        /** @scrutinizer ignore-unhandled */
106
+        @unlink($filename); // @ intentionally as file may not exist
107
+        $this->loaded = false;
108
+    }
109
+
110
+    /**
111
+     * @throws BuilderException
112
+     */
113
+    public function compile(int $rebuild = 0): Catalogue
114
+    {
115
+        // Exception on to many rebuild try
116
+        if ($rebuild > 3) {
117
+            throw new BuilderException('Failed to build language file');
118
+        }
119
+
120
+        // Check for file exist, create if no
121
+        $filename = $this->path . '/' . $this->getName() . '.php';
122
+        if (!file_exists($filename)) {
123
+            file_put_contents($filename, $this->compileCode());
124
+        }
125
+
126
+        // Link file and rebuild if error
127
+        try {
128
+            $this->checkForChanges($filename);
129
+            $this->link($filename);
130
+
131
+            if (!$this->catalogue instanceof Catalogue) {
132
+                throw new BuilderException('Catalogue is not implementing Catalogue');
133
+            }
134
+
135
+            return $this->catalogue;
136
+        } catch (Throwable $e) {
137
+            $this->unlink($filename);
138
+            return $this->compile(++$rebuild);
139
+        }
140
+    }
141
+
142
+    /**
143
+     * @param string $filename
144
+     */
145
+    protected function checkForChanges(string $filename): void
146
+    {
147
+        if (!$this->debug) {
148
+            return;
149
+        }
150
+
151
+        $cacheTime = (int) filemtime($filename);
152
+        foreach ($this->collection as $file) {
153
+            $file = new SplFileInfo($file);
154
+            $fileTime = $file->getMTime();
155
+            if ($fileTime > $cacheTime || ($this->catalogue && $fileTime > $this->catalogue->build())) {
156
+                throw new BuilderException('Rebuild required');
157
+            }
158
+        }
159
+
160
+        $this->onCheck($cacheTime);
161
+    }
162
+
163
+    /**
164
+     * Compile cache code
165
+     *
166
+     * @return string
167
+     */
168
+    protected function compileCode(): string
169
+    {
170
+        // Load messages, then generate code
171
+        $messages = $this->getMessages();
172
+        $this->onCompile($messages);
173
+
174
+        /*
175 175
 				do {
176 176
 					$className = $this->getName() . substr(md5((string) mt_rand()), 4, 8);
177 177
 				} while (class_exists($className));
178 178
 		*/
179 179
 
180
-		// File
181
-		$file = new PhpFile();
182
-		$file->setStrictTypes();
183
-		$file->setComment('This file was auto-generated');
184
-
185
-		$class = new ClassType();
186
-		$class->setExtends(Catalogue::class);
187
-
188
-		// Setup plural method
189
-		$method = $class->addMethod('plural');
190
-		$plural = Method::from((array) $this->plural->getPlural($this->locale));
191
-		$method->setParameters($plural->getParameters());
192
-		$parameters = $method->getParameters();
193
-		$method->setBody('return Bckp\Translator\PluralProvider::?($?);', [$plural->getName(), key($parameters)]);
194
-		$method->setReturnNullable($plural->isReturnNullable());
195
-		$method->setReturnType($plural->getReturnType());
196
-
197
-		// Messages & build time
198
-		$class->addMethod('locale')->setBody("return '{$this->getLocale()}';")->setReturnType('string');
199
-		$class->addMethod('build')->setBody('return ' . time() . ';')->setReturnType('int');
200
-		$class->addProperty('messages', $messages)->setType('array')->setStatic()->setVisibility('protected');
201
-
202
-		// Generate code
203
-		$code = (string) $file;
204
-		$code .= "\nreturn new class {$class};\n";
205
-
206
-		// Return string
207
-		return $code;
208
-	}
209
-
210
-	/**
211
-	 * Get all messages
212
-	 *
213
-	 * @return string[]
214
-	 * @throws FileInvalidException
215
-	 */
216
-	protected function getMessages(): array
217
-	{
218
-		$messages = [];
219
-
220
-		// Add files
221
-		foreach ($this->collection as $file) {
222
-			$info = new SplFileInfo($file);
223
-			$resource = strtolower($info->getBasename('.' . $this->locale . '.neon'));
224
-			foreach ($this->loadFile($file) as $key => $item) {
225
-				$messages[$resource . '.' . $key] = $item;
226
-			}
227
-		}
228
-
229
-		// Add dynamic translations
230
-		foreach ($this->dynamic as $resource => $callback) {
231
-			$resource = $namespace = strtolower($resource);
232
-			$locale = $this->locale;
233
-			$array = [];
234
-
235
-			$callback($array, $resource, $locale);
236
-
237
-			// @phpstan-ignore-next-line
238
-			foreach ($array as $key => $item) {
239
-				$messages[$namespace . '.' . $key] = $item;
240
-			}
241
-		}
242
-
243
-		return $messages;
244
-	}
245
-
246
-	/**
247
-	 * @param string $file
248
-	 * @return string[]
249
-	 * @throws PathInvalidException
250
-	 * @throws FileInvalidException
251
-	 */
252
-	protected function loadFile(string $file): array
253
-	{
254
-		if (!file_exists($file) || !is_readable($file)) {
255
-			throw new PathInvalidException("File '$file' not found or is not readable.");
256
-		}
257
-
258
-		$content = file_get_contents($file);
259
-		if (!$content) {
260
-			return [];
261
-		}
262
-
263
-		try {
264
-			$content = Neon::decode($content);
265
-			if (!is_array($content)) {
266
-				throw new RuntimeException('No array');
267
-			}
268
-		} catch (Throwable $e) {
269
-			throw new FileInvalidException(
270
-				"File '$file' do not contain array of translations",
271
-				$e->getCode(),
272
-				$e
273
-			);
274
-		}
275
-		return $content;
276
-	}
277
-
278
-	/**
279
-	 * Occurs when new catalogue is compiled, after all strings are loaded
280
-	 * @param array<array<string>|string> $messages
281
-	 */
282
-	private function onCompile(array &$messages): void
283
-	{
284
-		foreach ($this->onCompile as $callback) {
285
-			$locale = $this->locale;
286
-			$callback($messages, $locale);
287
-		}
288
-	}
289
-
290
-	public function getLocale(): string
291
-	{
292
-		return $this->locale;
293
-	}
294
-
295
-	private function onCheck(int $fileTime): void
296
-	{
297
-		foreach ($this->onCheck as $callback) {
298
-			$locale = $this->locale;
299
-			$callback($fileTime, $locale);
300
-		}
301
-	}
302
-
303
-	/**
304
-	 * Link catalogue if not already linked
305
-	 *
306
-	 * @param string $filename
307
-	 * @throws BuilderException
308
-	 */
309
-	private function link(string $filename): void
310
-	{
311
-		if ($this->loaded) {
312
-			return;
313
-		}
314
-
315
-		$this->catalogue = require $filename;
316
-		$this->loaded = true;
317
-	}
318
-
319
-	/**
320
-	 * @param callable $callback function(array &$messages, string $locale): void
321
-	 */
322
-	public function addCompileCallback(callable $callback): void
323
-	{
324
-		$this->onCompile[] = $callback;
325
-	}
326
-
327
-	/**
328
-	 * @param callable $callback function(string $locale): void
329
-	 */
330
-	public function addCheckCallback(callable $callback): void
331
-	{
332
-		$this->onCheck[] = $callback;
333
-	}
334
-
335
-	public function setDebugMode(bool $debug): self
336
-	{
337
-		$this->debug = $debug;
338
-		return $this;
339
-	}
180
+        // File
181
+        $file = new PhpFile();
182
+        $file->setStrictTypes();
183
+        $file->setComment('This file was auto-generated');
184
+
185
+        $class = new ClassType();
186
+        $class->setExtends(Catalogue::class);
187
+
188
+        // Setup plural method
189
+        $method = $class->addMethod('plural');
190
+        $plural = Method::from((array) $this->plural->getPlural($this->locale));
191
+        $method->setParameters($plural->getParameters());
192
+        $parameters = $method->getParameters();
193
+        $method->setBody('return Bckp\Translator\PluralProvider::?($?);', [$plural->getName(), key($parameters)]);
194
+        $method->setReturnNullable($plural->isReturnNullable());
195
+        $method->setReturnType($plural->getReturnType());
196
+
197
+        // Messages & build time
198
+        $class->addMethod('locale')->setBody("return '{$this->getLocale()}';")->setReturnType('string');
199
+        $class->addMethod('build')->setBody('return ' . time() . ';')->setReturnType('int');
200
+        $class->addProperty('messages', $messages)->setType('array')->setStatic()->setVisibility('protected');
201
+
202
+        // Generate code
203
+        $code = (string) $file;
204
+        $code .= "\nreturn new class {$class};\n";
205
+
206
+        // Return string
207
+        return $code;
208
+    }
209
+
210
+    /**
211
+     * Get all messages
212
+     *
213
+     * @return string[]
214
+     * @throws FileInvalidException
215
+     */
216
+    protected function getMessages(): array
217
+    {
218
+        $messages = [];
219
+
220
+        // Add files
221
+        foreach ($this->collection as $file) {
222
+            $info = new SplFileInfo($file);
223
+            $resource = strtolower($info->getBasename('.' . $this->locale . '.neon'));
224
+            foreach ($this->loadFile($file) as $key => $item) {
225
+                $messages[$resource . '.' . $key] = $item;
226
+            }
227
+        }
228
+
229
+        // Add dynamic translations
230
+        foreach ($this->dynamic as $resource => $callback) {
231
+            $resource = $namespace = strtolower($resource);
232
+            $locale = $this->locale;
233
+            $array = [];
234
+
235
+            $callback($array, $resource, $locale);
236
+
237
+            // @phpstan-ignore-next-line
238
+            foreach ($array as $key => $item) {
239
+                $messages[$namespace . '.' . $key] = $item;
240
+            }
241
+        }
242
+
243
+        return $messages;
244
+    }
245
+
246
+    /**
247
+     * @param string $file
248
+     * @return string[]
249
+     * @throws PathInvalidException
250
+     * @throws FileInvalidException
251
+     */
252
+    protected function loadFile(string $file): array
253
+    {
254
+        if (!file_exists($file) || !is_readable($file)) {
255
+            throw new PathInvalidException("File '$file' not found or is not readable.");
256
+        }
257
+
258
+        $content = file_get_contents($file);
259
+        if (!$content) {
260
+            return [];
261
+        }
262
+
263
+        try {
264
+            $content = Neon::decode($content);
265
+            if (!is_array($content)) {
266
+                throw new RuntimeException('No array');
267
+            }
268
+        } catch (Throwable $e) {
269
+            throw new FileInvalidException(
270
+                "File '$file' do not contain array of translations",
271
+                $e->getCode(),
272
+                $e
273
+            );
274
+        }
275
+        return $content;
276
+    }
277
+
278
+    /**
279
+     * Occurs when new catalogue is compiled, after all strings are loaded
280
+     * @param array<array<string>|string> $messages
281
+     */
282
+    private function onCompile(array &$messages): void
283
+    {
284
+        foreach ($this->onCompile as $callback) {
285
+            $locale = $this->locale;
286
+            $callback($messages, $locale);
287
+        }
288
+    }
289
+
290
+    public function getLocale(): string
291
+    {
292
+        return $this->locale;
293
+    }
294
+
295
+    private function onCheck(int $fileTime): void
296
+    {
297
+        foreach ($this->onCheck as $callback) {
298
+            $locale = $this->locale;
299
+            $callback($fileTime, $locale);
300
+        }
301
+    }
302
+
303
+    /**
304
+     * Link catalogue if not already linked
305
+     *
306
+     * @param string $filename
307
+     * @throws BuilderException
308
+     */
309
+    private function link(string $filename): void
310
+    {
311
+        if ($this->loaded) {
312
+            return;
313
+        }
314
+
315
+        $this->catalogue = require $filename;
316
+        $this->loaded = true;
317
+    }
318
+
319
+    /**
320
+     * @param callable $callback function(array &$messages, string $locale): void
321
+     */
322
+    public function addCompileCallback(callable $callback): void
323
+    {
324
+        $this->onCompile[] = $callback;
325
+    }
326
+
327
+    /**
328
+     * @param callable $callback function(string $locale): void
329
+     */
330
+    public function addCheckCallback(callable $callback): void
331
+    {
332
+        $this->onCheck[] = $callback;
333
+    }
334
+
335
+    public function setDebugMode(bool $debug): self
336
+    {
337
+        $this->debug = $debug;
338
+        return $this;
339
+    }
340 340
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
 			return;
149 149
 		}
150 150
 
151
-		$cacheTime = (int) filemtime($filename);
151
+		$cacheTime = (int)filemtime($filename);
152 152
 		foreach ($this->collection as $file) {
153 153
 			$file = new SplFileInfo($file);
154 154
 			$fileTime = $file->getMTime();
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
 
188 188
 		// Setup plural method
189 189
 		$method = $class->addMethod('plural');
190
-		$plural = Method::from((array) $this->plural->getPlural($this->locale));
190
+		$plural = Method::from((array)$this->plural->getPlural($this->locale));
191 191
 		$method->setParameters($plural->getParameters());
192 192
 		$parameters = $method->getParameters();
193 193
 		$method->setBody('return Bckp\Translator\PluralProvider::?($?);', [$plural->getName(), key($parameters)]);
@@ -200,7 +200,7 @@  discard block
 block discarded – undo
200 200
 		$class->addProperty('messages', $messages)->setType('array')->setStatic()->setVisibility('protected');
201 201
 
202 202
 		// Generate code
203
-		$code = (string) $file;
203
+		$code = (string)$file;
204 204
 		$code .= "\nreturn new class {$class};\n";
205 205
 
206 206
 		// Return string
Please login to merge, or discard this patch.