Completed
Push — master ( 2f10c4...363bc6 )
by Peter
06:39
created

I18NAbleTrait::setLang()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 41
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7.0046

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 41
ccs 21
cts 22
cp 0.9545
rs 6.7272
c 2
b 0
f 0
cc 7
eloc 22
nc 12
nop 2
crap 7.0046
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL or Commercial license.
5
 *
6
 * @package maslosoft/mangan
7
 * @licence AGPL or Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]>
9
 * @copyright Copyright (c) Maslosoft
10
 * @copyright Copyright (c) Others as mentioned in code
11
 * @link https://maslosoft.com/mangan/
12
 */
13
14
namespace Maslosoft\Mangan\Traits;
15
16
use Maslosoft\Mangan\Events\Event;
17
use Maslosoft\Mangan\Events\ModelEvent;
18
use Maslosoft\Mangan\Helpers\CompositionIterator;
19
use Maslosoft\Mangan\Interfaces\InternationalInterface;
20
use Maslosoft\Mangan\Meta\ManganMeta;
21
22
/**
23
 * I18N-able trait contains basic implementation of I18N feature. This covers
24
 * methods from `InternationalInterface`.
25
 *
26
 * Use this trait to provide internationalized columns for models.
27
 *
28
 * @see InternationalInterface
29
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
30
 */
31
trait I18NAbleTrait
32
{
33
34
	private $_lang = 'en';
35
	private $_rawI18N = [];
36
	private $_languages = ['en'];
37
	private $_defaultLanguage = 'en';
38
39
	/**
40
	 * Get current working language code
41
	 * @return string Language code
42
	 * @Ignored
43
	 */
44 72
	public function getLang()
45
	{
46 72
		return $this->_lang? : $this->getDefaultLanguage();
47
	}
48
49
	/**
50
	 * Get available languages
51
	 * @return string[]
52
	 * @Ignored
53
	 */
54 39
	public function getLanguages()
55
	{
56 39
		return $this->_languages;
57
	}
58
59
	/**
60
	 * Get i18n values with all languages.
61
	 * This returns all language values of all class fields. Class field names are
62
	 * keys for arrays of language values, with language codes as a keys.
63
	 *
64
	 * Example returned variable:
65
	 * ```php
66
	 * [
67
	 * 		'name' => [
68
	 * 			'en' => 'January',
69
	 * 			'pl' => 'Styczeń'
70
	 * 		],
71
	 * 		'description' => [
72
	 * 			'en' => 'First mothn of a year'
73
	 * 			'pl' => 'Pierwszy miesiąc roku'
74
	 * 		]
75
	 * ]
76
	 * ```
77
	 * @return mixed[] Associative array of language values
78
	 * @Ignored
79
	 */
80 31
	public function getRawI18N()
81
	{
82 31
		$meta = ManganMeta::create($this);
83 31
		$fields = $meta->properties('i18n');
84
85
		// Set current model value for current language for each property
86 31
		foreach ($fields as $name => $i18n)
87
		{
88
			// This is to keep rawi18n value in sync with current model value.
89 31
			$this->_rawI18N[$name][$this->getLang()] = $this->$name;
90
		}
91 31
		return $this->_rawI18N;
92
	}
93
94
	/**
95
	 * Set language code. This changes current model language.
96
	 * After setting language model attributes will store values in different locale.
97
	 *
98
	 * Language code must be previously set by `setLanguages`.
99
	 * When trying to set undefined language code, method will do nothing.
100
	 * When setting already choosen language code, method will also ignore this call.
101
	 * Example method calls:
102
	 * ```php
103
	 * // Set available languages
104
	 * $model->setLanguages(['en', 'pl']);
105
	 *
106
	 * // Will ignore as en is by default
107
	 * $model->setLang('en');
108
	 *
109
	 * // Will set pl as language
110
	 * $model->setLang('pl');
111
	 *
112
	 * // Will ignore as ru is not available
113
	 * $model->setLang('ru')
114
	 * ```
115
	 *
116
	 * For initial call, when there are no data set yet, `$triggetEvents`
117
	 * can be set to false to improve performance.
118
	 *
119
	 * @param string $code
120
	 * @param boolean $triggerEvents
121
	 * @Ignored
122
	 */
123 89
	public function setLang($code, $triggerEvents = true)
124
	{
125
		// Ensure that calling with empty code will not set language
126
		// to empty value
127 89
		if(empty($code))
128
		{
129 76
			return false;
130
		}
131 26
		if ($this->_lang === $code)
132
		{
133 23
			return false;
134
		}
135 15
		if (!in_array($code, $this->getLanguages()))
136
		{
137 11
			$this->_languages[] = $code;
138
		}
139 15
		if(!$triggerEvents)
140
		{
141 4
			$this->_lang = $code;
142 4
			return true;
143
		}
144
145 11
		$it = new CompositionIterator($this);
146 11
		$it->ofType(InternationalInterface::class);
147 11
		foreach($it as $model)
148
		{
149
			/* @var $model InternationalInterface */
150 2
			$model->setLang($code);
151
		}
152
153 9
		$event = new ModelEvent($this);
154 9
		$event->data = $code;
155 9
		if (!Event::valid($this, InternationalInterface::EventBeforeLangChange, $event))
156
		{
157
			return false;
158
		}
159 9
		$this->_changeAttributesLang($this->_lang, $code);
160 9
		$this->_lang = $code;
161 9
		Event::trigger($this, InternationalInterface::EventAfterLangChange, $event);
162 9
		return true;
163
	}
164
165
	/**
166
	 * Set available languages. This method accepts one parameter,
167
	 * array contaning language codes prefably in short ISO form.
168
	 *
169
	 * Example valid array and method calls:
170
	 *
171
	 * ```php
172
	 * $languages = ['en', 'pl', 'ru'];
173
	 * $model->setLanguages($languages);
174
	 * $model2->setLanguages(['en']);
175
	 * ```
176
	 *
177
	 * For initial call, when there are no data set yet, `$triggetEvents`
178
	 * can be set to false to improve performance.
179
	 *
180
	 * @param string[] $languages
181
	 * @param boolean $triggerEvents
182
	 * @Ignored
183
	 */
184 72
	public function setLanguages($languages, $triggerEvents = true)
185
	{
186 72
		if($triggerEvents)
187
		{
188 72
			$event = new ModelEvent($this);
189 72
			$event->data = $languages;
190 72
			if (!Event::valid($this, InternationalInterface::EventBeforeLanguagesSet, $event))
191
			{
192
				return;
193
			}
194
		}
195 72
		$this->_languages = $languages;
196 72
		if($triggerEvents)
197
		{
198 72
			Event::trigger($this, InternationalInterface::EventAfterLanguagesSet, $event);
199
		}
200 72
	}
201
202
	/**
203
	 * Set i18n values in all languages.
204
	 * This method must keep `$values` for further use, by method `getRawI18N`.
205
	 * @param mixed[] $values
206
	 * @Ignored
207
	 */
208 14
	public function setRawI18N($values)
209
	{
210 14
		$this->_rawI18N = $values;
211 14
	}
212
213
	/**
214
	 * Get default language used for I18N operations.
215
	 *
216
	 * If not previously set, will fall back to `en`.
217
	 *
218
	 * @return string
219
	 * @Ignored
220
	 */
221 9
	public function getDefaultLanguage()
222
	{
223 9
		return $this->_defaultLanguage? : 'en';
224
	}
225
226
	/**
227
	 * Set default language used for I18N operations. This language
228
	 * will be used if the `setLang` method was not called.
229
	 *
230
	 * The value should be language code, for example `en`
231
	 *
232
	 * @param string $language
233
	 * @Ignored
234
	 */
235 1
	public function setDefaultLanguage($language)
236
	{
237 1
		$this->_defaultLanguage = $language;
238 1
	}
239
240
	/**
241
	 * Change i18n attributes values to appropriate language
242
	 * @param string $fromCode
243
	 * @param string $toCode
244
	 */
245 9
	private function _changeAttributesLang($fromCode, $toCode)
246
	{
247 9
		$meta = ManganMeta::create($this);
248 9
		$fields = $meta->properties('i18n');
249 9
		$defaultLang = $this->getDefaultLanguage();
250 9
		foreach ($fields as $name => $i18n)
251
		{
252 9
			$current = $this->$name;
253 9
			if (isset($this->_rawI18N[$name]) && array_key_exists($toCode, $this->_rawI18N[$name]))
254
			{
255 4
				$new = $this->_rawI18N[$name][$toCode];
256
			}
257
			else
258
			{
259 9
				$i18n = $meta->field($name)->i18n;
260
261 9
				if($i18n->allowDefault && isset($this->_rawI18N[$name]) && array_key_exists($defaultLang, $this->_rawI18N[$name]))
262
				{
263 1
					$new = $this->_rawI18N[$name][$defaultLang];
264
				}
265 9
				elseif($i18n->allowAny && !empty($this->_rawI18N[$name]))
266
				{
267
					$wasFound = false;
268
					foreach($this->getLanguages() as $code)
269
					{
270
						if(!empty($this->_rawI18N[$name][$code]))
271
						{
272
							$new = $this->_rawI18N[$name][$code];
273
							$wasFound = true;
274
							break;
275
						}
276
					}
277
					if(!$wasFound)
278
					{
279
						$new = $meta->$name->default;
280
					}
281
				}
282
				else
283
				{
284 9
					$new = $meta->$name->default;
285
				}
286
			}
287 9
			$this->_rawI18N[$name][$fromCode] = $current;
288 9
			$this->$name = $new;
289
		}
290 9
	}
291
292
}
293