GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

LocaliseModelTranslation   F
last analyzed

Complexity

Total Complexity 241

Size/Duplication

Total Lines 1543
Duplicated Lines 8.04 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
dl 124
loc 1543
rs 0.8
c 0
b 0
f 0
wmc 241
lcom 2
cbo 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
B populateState() 0 55 6
A getTable() 0 4 1
A getContents() 0 18 3
F getItem() 36 566 113
A getForm() 0 30 5
A loadFormData() 0 4 1
A getFormFtp() 20 20 3
F preprocessForm() 14 343 44
F saveFile() 42 309 52
C save() 12 103 13

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like LocaliseModelTranslation often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use LocaliseModelTranslation, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package     Com_Localise
4
 * @subpackage  model
5
 *
6
 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
7
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
8
 */
9
10
defined('_JEXEC') or die;
11
12
jimport('joomla.filesystem.folder');
13
jimport('joomla.filesystem.file');
14
jimport('joomla.filesystem.stream');
15
jimport('joomla.client.helper');
16
jimport('joomla.access.rules');
17
18
/**
19
 * Translation Model class for the Localise component
20
 *
21
 * @since  1.0
22
 */
23
class LocaliseModelTranslation extends JModelAdmin
24
{
25
	protected $item;
26
27
	protected $contents;
28
29
	/**
30
	 * Method to auto-populate the model state.
31
	 *
32
	 * Note. Calling getState in this method will result in recursion.
33
	 *
34
	 * @param   string  $ordering   An optional ordering field.
35
	 * @param   string  $direction  An optional direction (asc|desc).
36
	 *
37
	 * @return  void
38
	 *
39
	 * @since   1.6
40
	 */
41
	protected function populateState($ordering = null, $direction = null)
42
	{
43
		$input = JFactory::getApplication()->input;
44
45
		// Get the infos
46
		$client   = $input->getCmd('client', '');
47
		$tag      = $input->getCmd('tag', '');
48
		$filename = $input->getCmd('filename', '');
49
		$storage  = $input->getCmd('storage', '');
50
51
		$this->setState('translation.client', !empty($client) ? $client : 'site');
52
		$this->setState('translation.tag', $tag);
53
		$this->setState('translation.filename', $filename);
54
		$this->setState('translation.storage', $storage);
55
56
		// Get the id
57
		$id = $input->getInt('id', '0');
58
		$this->setState('translation.id', $id);
59
60
		// Get the layout
61
		$layout = $input->getCmd('layout', 'edit');
62
		$this->setState('translation.layout', $layout);
63
64
		// Get the parameters
65
		$params = JComponentHelper::getParams('com_localise');
66
67
		// Get the reference tag
68
		$ref = $params->get('reference', 'en-GB');
69
		$this->setState('translation.reference', $ref);
70
71
		// Get the paths
72
		$path = LocaliseHelper::getTranslationPath($client, $tag, $filename, $storage);
73
74
		if ($filename == 'lib_joomla')
75
		{
76
			$refpath = LocaliseHelper::findTranslationPath('administrator', $ref, $filename);
77
78
			if (!JFile::exists($path))
79
			{
80
				$path2 = LocaliseHelper::getTranslationPath($client == 'administrator' ? 'site' : 'administrator', $tag, $filename, $storage);
81
82
				if (JFile::exists($path2))
83
				{
84
					$path = $path2;
85
				}
86
			}
87
		}
88
		else
89
		{
90
			$refpath = LocaliseHelper::findTranslationPath($client, $ref, $filename);
91
		}
92
93
		$this->setState('translation.path', $path);
94
		$this->setState('translation.refpath', $refpath);
95
	}
96
97
	/**
98
	 * Returns a Table object, always creating it.
99
	 *
100
	 * @param   type    $type    The table type to instantiate
101
	 * @param   string  $prefix  A prefix for the table class name. Optional.
102
	 * @param   array   $config  Configuration array for model. Optional.
103
	 *
104
	 * @return  JTable  A database object
105
	 */
106
	public function getTable($type = 'Localise', $prefix = 'LocaliseTable', $config = array())
107
	{
108
		return JTable::getInstance($type, $prefix, $config);
109
	}
110
111
	/**
112
	 * Get contents
113
	 *
114
	 * @return string
115
	 */
116
	public function getContents()
117
	{
118
		if (!isset($this->contents))
119
		{
120
			$path = $this->getState('translation.path');
121
122
			if (JFile::exists($path))
123
			{
124
				$this->contents = file_get_contents($path);
125
			}
126
			else
127
			{
128
				$this->contents = '';
129
			}
130
		}
131
132
		return $this->contents;
133
	}
134
135
	/**
136
	 * Get a translation
137
	 *
138
	 * @param   integer  $pk  The id of the primary key (Note unused by the function).
139
	 *
140
	 * @return  JObject|null  Object on success, null on failure.
141
	 */
142
	public function getItem($pk = null)
143
	{
144
		if (!isset($this->item))
145
		{
146
			$conf    = JFactory::getConfig();
147
			$caching = $conf->get('caching') >= 1;
148
149
			if ($caching)
150
			{
151
				$keycache   = $this->getState('translation.client') . '.' . $this->getState('translation.tag') . '.' .
152
					$this->getState('translation.filename') . '.' . 'translation';
153
				$cache      = JFactory::getCache('com_localise', '');
154
				$this->item = $cache->get($keycache);
155
156
				if ($this->item && $this->item->reference != $this->getState('translation.reference'))
157
				{
158
					$this->item = null;
159
				}
160
			}
161
			else
162
			{
163
				$this->item = null;
164
			}
165
166
			if (!$this->item)
167
			{
168
				$path = JFile::exists($this->getState('translation.path'))
169
					? $this->getState('translation.path')
170
					: $this->getState('translation.refpath');
171
172
				$params              = JComponentHelper::getParams('com_localise');
173
				$allow_develop       = $params->get('gh_allow_develop', 0);
174
				$gh_client           = $this->getState('translation.client');
175
				$tag                 = $this->getState('translation.tag');
176
				$reftag              = $this->getState('translation.reference');
177
				$refpath             = $this->getState('translation.refpath');
178
				$istranslation       = 0;
179
180
				if (!empty($tag) && $tag != $reftag)
181
				{
182
					$istranslation = 1;
183
				}
184
185
				$this->setState('translation.translatedkeys', array());
186
				$this->setState('translation.untranslatedkeys', array());
187
				$this->setState('translation.unchangedkeys', array());
188
				$this->setState('translation.textchangedkeys', array());
189
				$this->setState('translation.revisedchanges', array());
190
				$this->setState('translation.developdata', array());
191
192
				$translatedkeys   = $this->getState('translation.translatedkeys');
193
				$untranslatedkeys = $this->getState('translation.untranslatedkeys');
194
				$unchangedkeys    = $this->getState('translation.unchangedkeys');
195
				$textchangedkeys  = $this->getState('translation.textchangedkeys');
196
				$revisedchanges  = $this->getState('translation.revisedchanges');
197
				$developdata      = $this->getState('translation.developdata');
198
199
				$this->item = new JObject(
200
									array
201
										(
202
										'reference'           => $this->getState('translation.reference'),
203
										'bom'                 => 'UTF-8',
204
										'svn'                 => '',
205
										'version'             => '',
206
										'description'         => '',
207
										'creationdate'        => '',
208
										'author'              => '',
209
										'maincopyright'       => '',
210
										'additionalcopyright' => array(),
211
										'license'             => '',
212
										'exists'              => JFile::exists($this->getState('translation.path')),
213
										'istranslation'       => $istranslation,
214
										'developdata'         => (array) $developdata,
215
										'translatedkeys'      => (array) $translatedkeys,
216
										'untranslatedkeys'    => (array) $untranslatedkeys,
217
										'unchangedkeys'       => (array) $unchangedkeys,
218
										'textchangedkeys'     => (array) $textchangedkeys,
219
										'revisedchanges'      => (array) $revisedchanges,
220
										'unrevised'           => 0,
221
										'translatednews'      => 0,
222
										'unchangednews'       => 0,
223
										'translated'          => 0,
224
										'untranslated'        => 0,
225
										'unchanged'           => 0,
226
										'extra'               => 0,
227
										'total'               => 0,
228
										'linespath'           => 0,
229
										'linesrefpath'        => 0,
230
										'linesdevpath'        => 0,
231
										'linescustompath'     => 0,
232
										'complete'            => false,
233
										'source'              => '',
234
										'error'               => array()
235
										)
236
				);
237
238
				if (JFile::exists($path))
239
				{
240
					$devpath    = LocaliseHelper::searchDevpath($gh_client, $refpath);
241
					$custompath = LocaliseHelper::searchCustompath($gh_client, $refpath);
242
243
					if ($istranslation == 0 && $reftag == 'en-GB')
244
					{
245
						if (!empty($devpath))
246
						{
247
							if (!empty($custompath))
248
							{
249
								$this->item->source = LocaliseHelper::combineReferences($custompath, $devpath);
250
							}
251
							else
252
							{
253
								$this->item->source = LocaliseHelper::combineReferences($path, $devpath);
254
							}
255
						}
256
					}
257
					else
258
					{
259
						$this->item->source = file_get_contents($path);
260
					}
261
262
					$stream = new JStream;
263
					$stream->open($path);
264
					$begin  = $stream->read(4);
265
					$bom    = strtolower(bin2hex($begin));
266
267
					if ($bom == '0000feff')
268
					{
269
						$this->item->bom = 'UTF-32 BE';
270
					}
271
					else
272
					{
273
						if ($bom == 'feff0000')
274
						{
275
							$this->item->bom = 'UTF-32 LE';
276
						}
277
						else
278
						{
279
							if (substr($bom, 0, 4) == 'feff')
280
							{
281
								$this->item->bom = 'UTF-16 BE';
282
							}
283
							else
284
							{
285
								if (substr($bom, 0, 4) == 'fffe')
286
								{
287
									$this->item->bom = 'UTF-16 LE';
288
								}
289
							}
290
						}
291
					}
292
293
					$stream->seek(0);
294
					$continue   = true;
0 ignored issues
show
Unused Code introduced by
$continue is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
295
					$lineNumber = 0;
296
297
					$isTranslationsView = JFactory::getApplication()->input->get('view') == 'translations';
298
299
					while (!$stream->eof())
300
					{
301
						$line = $stream->gets();
302
						$lineNumber++;
303
304
						if ($line[0] == '#')
305
						{
306
							$this->item->error[] = $lineNumber;
307
						}
308
						elseif ($line[0] == ';')
309
						{
310
							if (preg_match('/^(;).*(\$Id.*\$)/', $line, $matches))
311
							{
312
								$this->item->svn = $matches[2];
313
							}
314
							elseif (preg_match('/(;)\s*@?(\pL+):?.*/', $line, $matches))
315
							{
316
								switch (strtolower($matches[2]))
317
								{
318
									case 'note':
319
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
320
										$this->item->complete = $this->item->complete || strtolower($matches2[3]) == 'complete';
321
										break;
322
									case 'version':
323
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
324
										$this->item->version = $matches2[3];
325
										break;
326
									case 'desc':
327
									case 'description':
328
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
329
										$this->item->description = $matches2[3];
330
										break;
331
									case 'date':
332
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
333
										$this->item->creationdate = $matches2[3];
334
										break;
335 View Code Duplication
									case 'author':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
336
										if ($params->get('author') && !$isTranslationsView)
337
										{
338
											$this->item->author = $params->get('author');
339
										}
340
										else
341
										{
342
											preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
343
											$this->item->author = $matches2[3];
344
										}
345
										break;
346
									case 'copyright':
347
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
348
349
										if (empty($this->item->maincopyright))
350
										{
351
											if ($params->get('copyright') && !$isTranslationsView)
352
											{
353
												$this->item->maincopyright = $params->get('copyright');
354
											}
355
											else
356
											{
357
												$this->item->maincopyright = $matches2[3];
358
											}
359
										}
360
361
										if (empty($this->item->additionalcopyright))
362
										{
363
											if ($params->get('additionalcopyright') && !$isTranslationsView)
364
											{
365
												$this->item->additionalcopyright[] = $params->get('additionalcopyright');
366
											}
367
											else
368
											{
369
												$this->item->additionalcopyright[] = $matches2[3];
370
											}
371
										}
372
										break;
373 View Code Duplication
									case 'license':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
374
										if ($params->get('license') && !$isTranslationsView)
375
										{
376
											$this->item->license = $params->get('license');
377
										}
378
										else
379
										{
380
											preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
381
											$this->item->license = $matches2[3];
382
										}
383
										break;
384
									case 'package':
385
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
386
										$this->item->package = $matches2[3];
387
										break;
388
									case 'subpackage':
389
										preg_match('/(;)\s*@?(\pL+):?\s+(.*)/', $line, $matches2);
390
										$this->item->subpackage = $matches2[3];
391
										break;
392
									case 'link':
393
										break;
394 View Code Duplication
									default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
										if (empty($this->item->author))
396
										{
397
											if ($params->get('author') && !$isTranslationsView)
398
											{
399
												$this->item->author = $params->get('author');
400
											}
401
											else
402
											{
403
												preg_match('/(;)\s*(.*)/', $line, $matches2);
404
												$this->item->author = $matches2[2];
405
											}
406
										}
407
										break;
408
								}
409
							}
410
						}
411
						else
412
						{
413
							break;
414
						}
415
					}
416
417
					if (empty($this->item->author) && $params->get('author') && !$isTranslationsView)
418
					{
419
						$this->item->author = $params->get('author');
420
					}
421
422
					if (empty($this->item->license) && $params->get('license') && !$isTranslationsView)
423
					{
424
						$this->item->license = $params->get('license');
425
					}
426
427
					if (empty($this->item->maincopyright) && $params->get('copyright') && !$isTranslationsView)
428
					{
429
						$this->item->maincopyright = $params->get('copyright');
430
					}
431
432
					if (empty($this->item->additionalcopyright) && $params->get('additionalcopyright') && !$isTranslationsView)
433
					{
434
						$this->item->additionalcopyright[] = $params->get('additionalcopyright');
435
					}
436
437
					while (!$stream->eof())
438
					{
439
						$line = $stream->gets();
440
						$lineNumber++;
441
						$line = str_replace('\"', '"_QQ_"', $line);
442
443
						if (!preg_match('/^(|(\[[^\]]*\])|([A-Z][A-Z0-9_\*\-\.]*\s*=(\s*(("[^"]*")|(_QQ_)))+))\s*(;.*)?$/', $line))
444
						{
445
							$this->item->error[] = $lineNumber;
446
						}
447
					}
448
449
					if ($tag != $reftag)
450
					{
451
						if (JFile::exists($custompath))
452
						{
453
							$this->item->linescustompath = count(file($custompath));
454
						}
455
					}
456
457
					$stream->close();
458
				}
459
460
				$this->item->additionalcopyright = implode("\n", $this->item->additionalcopyright);
461
462
				if ($this->getState('translation.layout') != 'raw' && empty($this->item->error))
463
				{
464
					$sections = LocaliseHelper::parseSections($this->getState('translation.path'));
465
466
						if (!empty($custompath))
467
						{
468
							$refsections = LocaliseHelper::parseSections($custompath);
469
						}
470
						else
471
						{
472
							$refsections = LocaliseHelper::parseSections($this->getState('translation.refpath'));
473
						}
474
475
					$develop_client_path = JPATH_ROOT
476
								. '/media/com_localise/develop/github/joomla-cms/en-GB/'
477
								. $gh_client;
478
					$develop_client_path = JFolder::makeSafe($develop_client_path);
479
					$ref_file            = basename($this->getState('translation.refpath'));
480
					$develop_file_path   = "$develop_client_path/$ref_file";
481
					$new_keys            = array();
482
483
					if (JFile::exists($develop_file_path) && $allow_develop == 1 && $reftag == 'en-GB')
484
					{
485
						$info                  = array();
486
						$info['client']        = $gh_client;
487
						$info['reftag']        = 'en-GB';
488
						$info['tag']           = 'en-GB';
489
						$info['filename']      = $ref_file;
490
						$info['istranslation'] = $istranslation;
491
492
						$develop_sections = LocaliseHelper::parseSections($develop_file_path);
493
						$developdata      = LocaliseHelper::getDevelopchanges($info, $refsections, $develop_sections);
494
						$developdata['develop_file_path'] = '';
495
496
						if ($developdata['extra_keys']['amount'] > 0  || $developdata['text_changes']['amount'] > 0)
497
						{
498
							if ($developdata['extra_keys']['amount'] > 0)
499
							{
500
								$new_keys = $developdata['extra_keys']['keys'];
501
							}
502
503
							if ($developdata['text_changes']['amount'] > 0)
504
							{
505
								$textchangedkeys = $developdata['text_changes']['keys'];
506
								$this->item->textchangedkeys = $textchangedkeys;
507
								$this->setState('translation.textchangedkeys', $textchangedkeys);
508
509
								$changesdata['client'] = $gh_client;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$changesdata was never initialized. Although not strictly required by PHP, it is generally a good practice to add $changesdata = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
510
								$changesdata['reftag'] = $reftag;
511
512
									if ($istranslation == 0)
513
									{
514
										$changesdata['tag'] = $reftag;
515
									}
516
									else
517
									{
518
										$changesdata['tag'] = $tag;
519
									}
520
521
								$changesdata['filename'] = $ref_file;
522
523
								foreach ($textchangedkeys as $key_changed)
524
								{
525
									$target_text = $developdata['text_changes']['ref_in_dev'][$key_changed];
526
									$source_text = $developdata['text_changes']['ref'][$key_changed];
527
528
									$changesdata['revised']       = '0';
529
									$changesdata['key']           = $key_changed;
530
									$changesdata['target_text']   = $target_text;
531
									$changesdata['source_text']   = $source_text;
532
									$changesdata['istranslation'] = $istranslation;
533
									$changesdata['catch_grammar'] = '0';
534
535
									$change_status = LocaliseHelper::searchRevisedvalue($changesdata);
536
									$revisedchanges[$key_changed] = $change_status;
537
538
									if ($change_status == 1)
539
									{
540
										$developdata['text_changes']['revised']++;
541
									}
542
									else
543
									{
544
										$developdata['text_changes']['unrevised']++;
545
									}
546
								}
547
548
								$this->item->revisedchanges = $revisedchanges;
549
								$this->setState('translation.revisedchanges', $revisedchanges);
550
							}
551
552
							// When develop changes are present, replace the reference keys
553
							$refsections = $develop_sections;
554
555
							// And store the path for future calls
556
							$developdata['develop_file_path'] = $develop_file_path;
557
						}
558
					}
559
560
					if (!empty($refsections['keys']))
561
					{
562
						foreach ($refsections['keys'] as $key => $string)
563
						{
564
							$this->item->total++;
565
566
							if (!empty($sections['keys']) && array_key_exists($key, $sections['keys']) && $sections['keys'][$key] != '')
567
							{
568
								if ($sections['keys'][$key] != $string && $istranslation == 1)
569
								{
570
									if (array_key_exists($key, $revisedchanges) && $revisedchanges[$key] == 0)
571
									{
572
										$this->item->unrevised++;
573
										$translatedkeys[] = $key;
574
									}
575
									elseif (in_array($key, $new_keys))
576
									{
577
										$this->item->translatednews++;
578
										$translatedkeys[] = $key;
579
									}
580
									else
581
									{
582
										$this->item->translated++;
583
										$translatedkeys[] = $key;
584
									}
585
								}
586
								elseif ($istranslation == 0)
587
								{
588
									if (array_key_exists($key, $revisedchanges) && $revisedchanges[$key] == 0)
589
									{
590
										$this->item->unrevised++;
591
									}
592
									elseif (in_array($key, $new_keys))
593
									{
594
										$untranslatedkeys[] = $key;
595
									}
596
597
									$this->item->translated++;
598
								}
599
								else
600
								{
601
									if (in_array($key, $new_keys))
602
									{
603
										$this->item->unchangednews++;
604
									}
605
									else
606
									{
607
										$this->item->unchanged++;
608
									}
609
610
									$unchangedkeys[] = $key;
611
								}
612
							}
613
							elseif (!array_key_exists($key, $sections['keys']))
614
							{
615
								$this->item->untranslated++;
616
								$untranslatedkeys[] = $key;
617
							}
618
						}
619
					}
620
621
					$this->item->translatedkeys   = $translatedkeys;
622
					$this->item->untranslatedkeys = $untranslatedkeys;
623
					$this->item->unchangedkeys    = $unchangedkeys;
624
					$this->item->developdata      = $developdata;
625
626
					$this->setState('translation.translatedkeys', $translatedkeys);
627
					$this->setState('translation.untranslatedkeys', $untranslatedkeys);
628
					$this->setState('translation.unchangedkeys', $unchangedkeys);
629
					$this->setState('translation.developdata', $developdata);
630
631
					if (!empty($sections['keys']) && $istranslation == 1)
632
					{
633
						foreach ($sections['keys'] as $key => $string)
634
						{
635
							if (empty($refsections['keys']) || !array_key_exists($key, $refsections['keys']))
636
							{
637
								$this->item->extra++;
638
							}
639
						}
640
					}
641
642
					$done = $this->item->translated + $this->item->translatednews + $this->item->unchangednews;
643
644
					$this->item->completed = $this->item->total
645
						? intval(100 * $done / $this->item->total)
646
						: 100;
647
648
					$this->item->complete = $this->item->complete == 1 && $this->item->untranslated == 0 && $this->item->unrevised == 0
649
						? 1
650
						: ($this->item->completed == 100
651
							? 1
652
							: 0);
653
				}
654
655
				if ($this->getState('translation.id'))
656
				{
657
					$table = $this->getTable();
658
					$table->load($this->getState('translation.id'));
659
					$user = JFactory::getUser($table->checked_out);
660
					$this->item->setProperties($table->getProperties());
661
662
					if ($this->item->checked_out == JFactory::getUser()->id)
663
					{
664
						$this->item->checked_out = 0;
665
					}
666
667
					$this->item->editor = JText::sprintf('COM_LOCALISE_TEXT_TRANSLATION_EDITOR', $user->name, $user->username);
668
				}
669
670
				if ($caching)
671
				{
672
					$cache->store($this->item, $keycache);
0 ignored issues
show
Bug introduced by
The variable $cache does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $keycache does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
673
				}
674
675
				// Count the number of lines in the ini file to check max_input_vars
676
				if ($tag != $reftag)
677
				{
678
					if (JFile::exists($path))
679
					{
680
						$this->item->linespath = count(file($path));
681
					}
682
683
					if (JFile::exists($refpath))
684
					{
685
						$this->item->linesrefpath = count(file($refpath));
686
					}
687
688
					if ($this->getState('translation.layout') != 'raw')
689
					{
690
						if (isset($develop_file_path) && JFile::exists($develop_file_path))
691
						{
692
							$this->item->linesdevpath = count(file($develop_file_path));
693
						}
694
					}
695
				}
696
				else
697
				{
698
					if (JFile::exists($path))
699
					{
700
						$this->item->linespath = count(file($path));
701
					}
702
				}
703
			}
704
		}
705
706
		return $this->item;
707
	}
708
709
	/**
710
	 * Method to get the record form.
711
	 *
712
	 * @param   array    $data      Data for the form.
713
	 * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
714
	 *
715
	 * @return  mixed  A JForm object on success, false on failure
716
	 */
717
	public function getForm($data = array(), $loadData = true)
718
	{
719
		// Get the form.
720
		$form = $this->loadForm('com_localise.translation', 'translation', array('control'   => 'jform', 'load_data' => $loadData));
721
722
		$params = JComponentHelper::getParams('com_localise');
723
724
		// Set fields readonly if localise global params exist
725
		if ($params->get('author'))
726
		{
727
			$form->setFieldAttribute('author', 'readonly', 'true');
728
		}
729
730
		if ($params->get('copyright'))
731
		{
732
			$form->setFieldAttribute('maincopyright', 'readonly', 'true');
733
		}
734
735
		if ($params->get('additionalcopyright'))
736
		{
737
			$form->setFieldAttribute('additionalcopyright', 'readonly', 'true');
738
		}
739
740
		if ($params->get('license'))
741
		{
742
			$form->setFieldAttribute('license', 'readonly', 'true');
743
		}
744
745
		return $form;
746
	}
747
748
	/**
749
	 * Method to get the data that should be injected in the form.
750
	 *
751
	 * @return  array  The default data is an empty array.
752
	 */
753
	protected function loadFormData()
754
	{
755
		return $this->getItem();
756
	}
757
758
	/**
759
	 * Method to get the ftp form.
760
	 *
761
	 * @return  mixed  A JForm object on success, false on failure or not ftp
762
	 */
763 View Code Duplication
	public function getFormFtp()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
764
	{
765
		// Get the form.
766
		$form = $this->loadForm('com_localise.ftp', 'ftp');
767
768
		if (empty($form))
769
		{
770
			return false;
771
		}
772
773
		// Check for an error.
774
		if (JError::isError($form))
775
		{
776
			$this->setError($form->getMessage());
777
778
			return false;
779
		}
780
781
		return $form;
782
	}
783
784
	/**
785
	 * Method to allow derived classes to preprocess the form.
786
	 *
787
	 * @param   JForm   $form   A form object.
788
	 * @param   mixed   $item   The data expected for the form.
789
	 * @param   string  $group  The name of the plugin group to import (defaults to "content").
790
	 *
791
	 * @throws  Exception if there is an error in the form event.
792
	 * @return  JForm
793
	 */
794
	protected function preprocessForm(JForm $form, $item, $group = 'content')
795
	{
796
		// Initialize variables.
797
		$filename = $this->getState('translation.filename');
798
		$client   = $this->getState('translation.client');
799
		$tag      = $this->getState('translation.tag');
800
		$origin   = LocaliseHelper::getOrigin($filename, $client);
801
		$app      = JFactory::getApplication();
802
		$false    = false;
0 ignored issues
show
Unused Code introduced by
$false is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
803
804
		$have_develop        = 0;
805
		$developdata         = array();
806
		$revisedchanges      = array();
807
		$istranslation       = '';
808
		$extras_amount       = 0;
0 ignored issues
show
Unused Code introduced by
$extras_amount is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
809
		$text_changes_amount = 0;
0 ignored issues
show
Unused Code introduced by
$text_changes_amount is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
810
811
		// Compute all known languages
812
		static $languages = array();
813
		jimport('joomla.language.language');
814
815
		if (!array_key_exists($client, $languages))
816
		{
817
			$languages[$client] = JLanguage::getKnownLanguages(constant('LOCALISEPATH_' . strtoupper($client)));
818
		}
819
820
		if (is_object($item))
821
		{
822
			$form->setFieldAttribute('legend', 'unchanged', $item->unchanged, 'legend');
823
			$form->setFieldAttribute('legend', 'translated', $item->translated, 'legend');
824
			$form->setFieldAttribute('legend', 'untranslated', $item->total - $item->translated - $item->unchanged, 'legend');
825
			$form->setFieldAttribute('legend', 'extra', $item->extra, 'legend');
826
827
			$developdata    = $item->developdata;
828
			$revisedchanges = $item->revisedchanges;
829
			$istranslation  = $item->istranslation;
830
		}
831
832
		if ($this->getState('translation.layout') != 'raw')
833
		{
834
			$this->setState('translation.devpath', '');
835
836
			if (!empty($developdata))
837
			{
838
				$extras_amount       = $developdata['extra_keys']['amount'];
839
				$text_changes_amount = $developdata['text_changes']['amount'];
840
				$refpath             = $this->getState('translation.refpath');
841
842
				$custompath          = LocaliseHelper::searchCustompath($client, $refpath);
843
844
				if ($istranslation == '0')
845
				{
846
					if (!empty($custompath))
847
					{
848
						$refpath     = $custompath;
849
						$path        = $refpath;
0 ignored issues
show
Unused Code introduced by
$path is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
850
						$refsections = LocaliseHelper::parseSections($refpath);
851
						$sections    = $refsections;
852
					}
853
					else
854
					{
855
						$refpath     = $this->getState('translation.refpath');
856
						$path        = $refpath;
0 ignored issues
show
Unused Code introduced by
$path is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
857
						$refsections = LocaliseHelper::parseSections($refpath);
858
						$sections    = $refsections;
859
					}
860
				}
861
				else
862
				{
863
					if (!empty($custompath))
864
					{
865
						$refpath     = $custompath;
866
						$path        = $this->getState('translation.path');
867
						$refsections = LocaliseHelper::parseSections($refpath);
868
						$sections    = LocaliseHelper::parseSections($path);
869
					}
870 View Code Duplication
					else
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
871
					{
872
						$refpath     = $this->getState('translation.refpath');
873
						$path        = $this->getState('translation.path');
874
						$refsections = LocaliseHelper::parseSections($refpath);
875
						$sections    = LocaliseHelper::parseSections($path);
876
					}
877
				}
878
879
				if ($extras_amount > 0  || $text_changes_amount > 0)
880
				{
881
					$have_develop      = 1;
882
					$develop_file_path = $developdata['develop_file_path'];
883
					$develop_sections  = LocaliseHelper::parseSections($develop_file_path);
884
					$oldref            = $refsections;
885
					$refsections       = $develop_sections;
886
					$refpath           = $develop_file_path;
887
888
					$this->setState('translation.devpath', $develop_file_path);
889
				}
890
			}
891 View Code Duplication
			else
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
892
			{
893
				$path        = $this->getState('translation.path');
894
				$refpath     = $this->getState('translation.refpath');
895
				$sections    = LocaliseHelper::parseSections($path);
896
				$refsections = LocaliseHelper::parseSections($refpath);
897
			}
898
899
			$addform     = new SimpleXMLElement('<form />');
900
901
			$group = $addform->addChild('fields');
902
			$group->addAttribute('name', 'strings');
903
904
			$fieldset = $group->addChild('fieldset');
905
			$fieldset->addAttribute('name', 'JDEFAULT');
906
			$fieldset->addAttribute('label', 'JDEFAULT');
907
908
			if (JFile::exists($refpath))
909
			{
910
				$stream = new JStream;
911
				$stream->open($refpath);
912
				$header     = true;
913
				$lineNumber = 0;
914
915
				while (!$stream->eof())
916
				{
917
					$line = $stream->gets();
918
					$lineNumber++;
919
920
					// Blank lines
921
					if (preg_match('/^\s*$/', $line))
922
					{
923
						$header = true;
924
						$field  = $fieldset->addChild('field');
925
						$field->addAttribute('label', '');
926
						$field->addAttribute('type', 'spacer');
927
						$field->addAttribute('class', 'text');
928
						continue;
929
					}
930
					// Section lines
931
					elseif (preg_match('/^\[([^\]]*)\]\s*$/', $line, $matches))
932
					{
933
						$header = false;
934
						$form->load($addform, false);
935
						$section = $matches[1];
936
						$addform = new SimpleXMLElement('<form />');
937
						$group   = $addform->addChild('fields');
938
						$group->addAttribute('name', 'strings');
939
						$fieldset = $group->addChild('fieldset');
940
						$fieldset->addAttribute('name', $section);
941
						$fieldset->addAttribute('label', $section);
942
						continue;
943
					}
944
					// Comment lines
945
					elseif (!$header && preg_match('/^;(.*)$/', $line, $matches))
946
					{
947
						$key   = $matches[1];
948
						$field = $fieldset->addChild('field');
949
						$field->addAttribute('label', $key);
950
						$field->addAttribute('type', 'spacer');
951
						$field->addAttribute('class', 'text');
952
						continue;
953
					}
954
					// Key lines
955
					elseif (preg_match('/^([A-Z][A-Z0-9_\*\-\.]*)\s*=/', $line, $matches))
956
					{
957
						$header     = false;
958
						$key        = $matches[1];
959
						$field      = $fieldset->addChild('field');
960
961
						if ($have_develop == '1' && $istranslation == '0' && array_key_exists($key, $oldref['keys']))
962
						{
963
							$string = $oldref['keys'][$key];
0 ignored issues
show
Bug introduced by
The variable $oldref does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
964
							$translated = isset($sections['keys'][$key]);
965
							$modified   = $translated && $sections['keys'][$key] != $oldref['keys'][$key];
966
						}
967
						else
968
						{
969
							$string = $refsections['keys'][$key];
970
							$translated = isset($sections['keys'][$key]);
971
							$modified   = $translated && $sections['keys'][$key] != $refsections['keys'][$key];
972
						}
973
974
						$status     = $modified
975
							? 'translated'
976
							: ($translated
977
								? 'unchanged'
978
								: 'untranslated');
979
						$default    = $translated
980
							? $sections['keys'][$key]
981
							: '';
982
983
						$field->addAttribute('istranslation', $istranslation);
984
						$field->addAttribute('istextchange', 0);
985
						$field->addAttribute('isextraindev', 0);
986
987
						if ($have_develop == '1' && in_array($key, $developdata['text_changes']['keys']))
988
						{
989
							$change     = $developdata['text_changes']['diff'][$key];
990
							$sourcetext = $developdata['text_changes']['ref'][$key];
991
							$targettext = $developdata['text_changes']['ref_in_dev'][$key];
992
993
							$label   = '<b>'
994
								. $key
995
								. '</b><br /><p class="text_changes">'
996
								. $change
997
								. '</p>';
998
999
							$field->attributes()->istextchange = 1;
1000
							$field->addAttribute('changestatus', $revisedchanges[$key]);
1001
							$field->addAttribute('sourcetext', $sourcetext);
1002
							$field->addAttribute('targettext', $targettext);
1003
						}
1004
						elseif ($have_develop == '1' && in_array($key, $developdata['extra_keys']['keys']))
1005
						{
1006
							$label   = '<span class="new_word"><b>['
1007
								. JText::_('COM_LOCALISE_NEW_KEY_IN_DEVELOP')
1008
								. ']</b> </span><b>'
1009
								. $key
1010
								. '</b><br />'
1011
								. htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
1012
1013
							$field->attributes()->isextraindev = 1;
1014
						}
1015
						else
1016
						{
1017
							$label   = '<b>'
1018
								. $key
1019
								. '</b><br />'
1020
								. htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
1021
						}
1022
1023
						$field->addAttribute('status', $status);
1024
						$field->addAttribute('description', $string);
1025
1026
						if ($default)
1027
						{
1028
							$field->addAttribute('default', $default);
1029
						}
1030
						else
1031
						{
1032
							$field->addAttribute('default', $string);
1033
						}
1034
1035
						$field->addAttribute('label', $label);
1036
						$field->addAttribute('name', $key);
1037
						$field->addAttribute('type', 'key');
1038
						$field->addAttribute('filter', 'raw');
1039
						continue;
1040
					}
1041
					elseif (!preg_match('/^(|(\[[^\]]*\])|([A-Z][A-Z0-9_\*\-\.]*\s*=(\s*(("[^"]*")|(_QQ_)))+))\s*(;.*)?$/', $line))
1042
					{
1043
						$this->item->error[] = $lineNumber;
1044
					}
1045
				}
1046
1047
				$stream->close();
1048
				$newstrings = false;
1049
1050
				if (!empty($sections['keys']))
1051
				{
1052
					foreach ($sections['keys'] as $key => $string)
1053
					{
1054
						if (!isset($refsections['keys'][$key]))
1055
						{
1056
							if (!$newstrings)
1057
							{
1058
								$newstrings = true;
1059
								$form->load($addform, false);
1060
								$section = 'COM_LOCALISE_TEXT_TRANSLATION_NOTINREFERENCE';
1061
								$addform = new SimpleXMLElement('<form />');
1062
								$group   = $addform->addChild('fields');
1063
								$group->addAttribute('name', 'strings');
1064
								$fieldset = $group->addChild('fieldset');
1065
								$fieldset->addAttribute('name', $section);
1066
								$fieldset->addAttribute('label', $section);
1067
							}
1068
1069
							$field   = $fieldset->addChild('field');
1070
							$status  = 'extra';
1071
							$default = $string;
1072
							$label   = '<b>' . $key . '</b>';
1073
							$field->addAttribute('status', $status);
1074
							$field->addAttribute('description', $string);
1075
1076
							if ($default)
1077
							{
1078
								$field->addAttribute('default', $default);
1079
							}
1080
							else
1081
							{
1082
								$field->addAttribute('default', $string);
1083
							}
1084
1085
							$field->addAttribute('label', $label);
1086
							$field->addAttribute('name', $key);
1087
							$field->addAttribute('type', 'key');
1088
							$field->addAttribute('filter', 'raw');
1089
						}
1090
					}
1091
				}
1092
			}
1093
1094
			$form->load($addform, false);
1095
		}
1096
1097
		// Check the session for previously entered form data.
1098
		$data = $app->getUserState('com_localise.edit.translation.data', array());
1099
1100
		// Bind the form data if present.
1101
		if (!empty($data))
1102
		{
1103
			$form->bind($data);
1104
		}
1105
1106
		if ($origin != '_thirdparty' && $origin != '_override')
1107
		{
1108
			$packages = LocaliseHelper::getPackages();
1109
			$package  = $packages[$origin];
1110
1111
			if (!empty($package->author))
1112
			{
1113
				$form->setValue('author', $package->author);
1114
				$form->setFieldAttribute('author', 'readonly', 'true');
1115
			}
1116
1117
			if (!empty($package->copyright))
1118
			{
1119
				$form->setValue('maincopyright', $package->copyright);
1120
				$form->setFieldAttribute('maincopyright', 'readonly', 'true');
1121
			}
1122
1123
			if (!empty($package->license))
1124
			{
1125
				$form->setValue('license', $package->license);
1126
				$form->setFieldAttribute('license', 'readonly', 'true');
1127
			}
1128
		}
1129
1130
		if ($form->getValue('description') == '' && array_key_exists($tag, $languages[$client]))
1131
		{
1132
			$form->setValue('description', $filename . ' ' . $languages[$client][$tag]['name']);
1133
		}
1134
1135
		return $form;
1136
	}
1137
1138
	/**
1139
	 * Save a file
1140
	 *
1141
	 * @param   array  $data  Array that represents a file
1142
	 *
1143
	 * @return bool
1144
	 */
1145
	public function saveFile($data)
1146
	{
1147
		$client     = $this->getState('translation.client');
1148
		$tag        = $this->getState('translation.tag');
1149
		$reftag     = $this->getState('translation.reference');
1150
		$path       = $this->getState('translation.path');
1151
		$refpath    = $this->getState('translation.refpath');
1152
		$devpath    = LocaliseHelper::searchDevpath($client, $refpath);
1153
		$custompath = LocaliseHelper::searchCustompath($client, $refpath);
1154
		$exists     = JFile::exists($path);
1155
		$refexists  = JFile::exists($refpath);
1156
1157
		if ($refexists && !empty($devpath))
1158
		{
1159
			if ($reftag == 'en-GB' && $tag == 'en-GB' && !empty($custompath))
1160
			{
1161
				$params             = JComponentHelper::getParams('com_localise');
1162
				$customisedref      = $params->get('customisedref', '0');
1163
				$custom_short_path  = '../media/com_localise/customisedref/github/'
0 ignored issues
show
Unused Code introduced by
$custom_short_path is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1164
							. $client
1165
							. '/'
1166
							. $customisedref;
1167
1168
				// The saved file is not using the core language folders.
1169
				$path   = $custompath;
1170
				$exists = JFile::exists($path);
1171
1172
				$ref_file         = basename($refpath);
1173
				$custom_file_path = JFolder::makeSafe("$custompath/$ref_file");
0 ignored issues
show
Unused Code introduced by
$custom_file_path is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1174
			}
1175
			elseif ($reftag == 'en-GB' &&  $tag != 'en-GB')
1176
			{
1177
				// It is a translation with the file in develop as reference.
1178
				$refpath = $devpath;
1179
			}
1180
		}
1181
1182
		// Set FTP credentials, if given.
1183
		JClientHelper::setCredentialsFromRequest('ftp');
1184
		$ftp = JClientHelper::getCredentials('ftp');
1185
1186
		// Try to make the file writeable.
1187 View Code Duplication
		if ($exists && !$ftp['enabled'] && JPath::isOwner($path) && !JPath::setPermissions($path, '0644'))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1188
		{
1189
			$this->setError(JText::sprintf('COM_LOCALISE_ERROR_TRANSLATION_WRITABLE', $path));
1190
1191
			return false;
1192
		}
1193
1194
		if (array_key_exists('source', $data))
1195
		{
1196
			$contents = $data['source'];
1197
		}
1198
		else
1199
		{
1200
			$data['description']  = str_replace(array("\r\n", "\n", "\r"), " ", $data['description']);
1201
			$additionalcopyrights = trim($data['additionalcopyright']);
1202
1203
			if (empty($additionalcopyrights))
1204
			{
1205
				$additionalcopyrights = array();
1206
			}
1207
			else
1208
			{
1209
				$additionalcopyrights = explode("\n", $additionalcopyrights);
1210
			}
1211
1212
			$contents2 = '';
1213
1214
			if (!empty($data['svn']))
1215
			{
1216
				$contents2 .= "; " . $data['svn'] . "\n;\n";
1217
			}
1218
1219
			if (!empty($data['package']))
1220
			{
1221
				$contents2 .= "; @package     " . $data['package'] . "\n";
1222
			}
1223
1224
			if (!empty($data['subpackage']))
1225
			{
1226
				$contents2 .= "; @subpackage  " . $data['subpackage'] . "\n";
1227
			}
1228
1229
			if (!empty($data['description']) && $data['description'] != '[Description] [Name of language]([Country code])')
1230
			{
1231
				$contents2 .= "; @description " . $data['description'] . "\n";
1232
			}
1233
1234
			if (!empty($data['version']))
1235
			{
1236
				$contents2 .= "; @version     " . $data['version'] . "\n";
1237
			}
1238
1239
			if (!empty($data['creationdate']))
1240
			{
1241
				$contents2 .= "; @date        " . $data['creationdate'] . "\n";
1242
			}
1243
1244
			if (!empty($data['author']))
1245
			{
1246
				$contents2 .= "; @author      " . $data['author'] . "\n";
1247
			}
1248
1249
			if (!empty($data['maincopyright']))
1250
			{
1251
				$contents2 .= "; @copyright   " . $data['maincopyright'] . "\n";
1252
			}
1253
1254
			foreach ($additionalcopyrights as $copyright)
1255
			{
1256
				$contents2 .= "; @copyright   " . $copyright . "\n";
1257
			}
1258
1259
			if (!empty($data['license']))
1260
			{
1261
				$contents2 .= "; @license     " . $data['license'] . "\n";
1262
			}
1263
1264
			if (array_key_exists('complete', $data) && ($data['complete'] == '1'))
1265
			{
1266
				$this->setState('translation.complete', 1);
1267
				$contents2 .= "; @note        Complete\n";
1268
			}
1269
			else
1270
			{
1271
				$this->setState('translation.complete', 0);
1272
			}
1273
1274
			$contents2 .= "; @note        Client " . ucfirst($client) . "\n";
1275
			$contents2 .= "; @note        All ini files need to be saved as UTF-8\n\n";
1276
1277
			$contents = array();
1278
			$stream   = new JStream;
1279
1280
			if ($exists)
1281
			{
1282
				$stream->open($path);
1283
1284 View Code Duplication
				while (!$stream->eof())
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1285
				{
1286
					$line = $stream->gets();
1287
1288
					// Comment lines
1289
					if (preg_match('/^(;.*)$/', $line, $matches))
1290
					{
1291
						// $contents[] = $matches[1]."\n";
1292
					}
1293
					else
1294
					{
1295
						break;
1296
					}
1297
				}
1298
1299
				if ($refexists)
1300
				{
1301
					$stream->close();
1302
					$stream->open($refpath);
1303
1304 View Code Duplication
					while (!$stream->eof())
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1305
					{
1306
						$line = $stream->gets();
1307
1308
						// Comment lines
1309
						if (!preg_match('/^(;.*)$/', $line, $matches))
1310
						{
1311
							break;
1312
						}
1313
					}
1314
				}
1315
			}
1316
			else
1317
			{
1318
				$stream->open($refpath);
1319
1320
				while (!$stream->eof())
1321
				{
1322
					$line = $stream->gets();
1323
1324
					// Comment lines
1325 View Code Duplication
					if (preg_match('/^(;.*)$/', $line, $matches))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1326
					{
1327
						$contents[] = $matches[1] . "\n";
1328
					}
1329
					else
1330
					{
1331
						break;
1332
					}
1333
				}
1334
			}
1335
1336
			$strings = $data['strings'];
1337
1338
			while (!$stream->eof())
1339
			{
1340
			// Mounting the language file in this way will help to avoid save files with errors at the content.
1341
1342
				// Blank lines
1343
				if (preg_match('/^\s*$/', $line))
1344
				{
1345
					$contents[] = "\n";
1346
				}
1347
				// Comments lines
1348
				elseif (preg_match('/^(;.*)$/', $line, $matches))
0 ignored issues
show
Bug introduced by
The variable $line does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1349
				{
1350
					$contents[] = $matches[1] . "\n";
1351
				}
1352
				// Section lines
1353 View Code Duplication
				elseif (preg_match('/^\[([^\]]*)\]\s*$/', $line, $matches))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1354
				{
1355
					$contents[] = "[" . $matches[1] . "]\n";
1356
				}
1357
				// Key lines
1358
				elseif (preg_match('/^([A-Z][A-Z0-9_\*\-\.]*)\s*=/', $line, $matches))
1359
				{
1360
					$key = $matches[1];
1361
1362
					if (isset($strings[$key]))
1363
					{
1364
						$contents[] = $key . '="' . str_replace('"', '\"', $strings[$key]) . "\"\n";
1365
						unset($strings[$key]);
1366
					}
1367
				}
1368
				// Content with EOL
1369
				elseif (preg_split("/\\r\\n|\\r|\\n/", $line))
1370
				{
1371
					$application = JFactory::getApplication();
1372
					$application->enqueueMessage(JText::sprintf('COM_LOCALISE_WRONG_LINE_CONTENT', htmlspecialchars($line)), 'warning');
1373
				}
1374
				// Wrong lines
1375
				else
1376
				{
1377
					$application = JFactory::getApplication();
1378
					$application->enqueueMessage(JText::sprintf('COM_LOCALISE_WRONG_LINE_CONTENT', htmlspecialchars($line)), 'warning');
1379
				}
1380
1381
				$line = $stream->gets();
1382
			}
1383
1384
			if (!empty($strings))
1385
			{
1386
				$contents[] = "\n[New Strings]\n\n";
1387
1388
				foreach ($strings as $key => $string)
1389
				{
1390
					$contents[] = $key . '="' . str_replace('"', '/"', $string) . "\"\n";
1391
				}
1392
			}
1393
1394
			$stream->close();
1395
			$contents = implode($contents);
1396
			$contents = $contents2 . $contents;
1397
		}
1398
1399
		// Make sure EOL is Unix
1400
		$contents = str_replace(array("\r\n", "\n", "\r"), "\n", $contents);
1401
1402
		$return = JFile::write($path, $contents);
1403
1404
		// Try to make the template file unwriteable.
1405
1406
		// Get the parameters
1407
		$coparams = JComponentHelper::getParams('com_localise');
1408
1409
		// Get the file save permission
1410
		$fsper = $coparams->get('filesavepermission', '0444');
1411
1412
		if (!$ftp['enabled'] && JPath::isOwner($path) && !JPath::setPermissions($path, $fsper))
1413
		{
1414
			$this->setError(JText::sprintf('COM_LOCALISE_ERROR_TRANSLATION_UNWRITABLE', $path));
1415
1416
			return false;
1417
		}
1418
		else
1419
		{
1420
			if (!$return)
1421
			{
1422
				$this->setError(JText::sprintf('COM_LOCALISE_ERROR_TRANSLATION_FILESAVE', $path));
1423
1424
				return false;
1425
			}
1426
			elseif ($reftag == 'en-GB' && $tag == 'en-GB' && !empty($custompath))
1427
			{
1428
				$params             = JComponentHelper::getParams('com_localise');
1429
				$customisedref      = $params->get('customisedref', '0');
1430
				$custom_short_path  = '../media/com_localise/customisedref/github/'
1431
							. $client
1432
							. '/'
1433
							. $customisedref;
1434
1435
				JFactory::getApplication()->enqueueMessage(
1436
					JText::_('COM_LOCALISE_NOTICE_CUSTOM_EN_GB_FILE_SAVED') . $custom_short_path,
1437
					'notice');
1438
			}
1439
		}
1440
1441
		// Remove the cache
1442
		$conf    = JFactory::getConfig();
1443
		$caching = $conf->get('caching') >= 1;
1444
1445
		if ($caching)
1446
		{
1447
			$keycache = $this->getState('translation.client') . '.'
1448
				. $this->getState('translation.tag') . '.'
1449
				. $this->getState('translation.filename') . '.' . 'translation';
1450
			$cache    = JFactory::getCache('com_localise', '');
1451
			$cache->remove($keycache);
1452
		}
1453
	}
1454
1455
	/**
1456
	 * Saves a translation
1457
	 *
1458
	 * @param   array  $data  translation to be saved
1459
	 *
1460
	 * @return bool
1461
	 */
1462
	public function save($data)
1463
	{
1464
		// Fix DOT saving issue
1465
		$input = JFactory::getApplication()->input;
1466
1467
		$formData = $input->get('jform', array(), 'ARRAY');
1468
1469
		if (!empty($formData['strings']))
1470
		{
1471
			$data['strings'] = $formData['strings'];
1472
1473
			if (!empty($formData['text_changes']))
1474
			{
1475
				$data['text_changes'] = $formData['text_changes'];
1476
				$data['source_text_changes'] = $formData['source_text_changes'];
1477
				$data['target_text_changes'] = $formData['target_text_changes'];
1478
1479
				$changes_data = array();
1480
				$changes_data['client'] = $this->getState('translation.client');
1481
				$changes_data['reftag'] = $this->getState('translation.reference');
1482
				$changes_data['tag'] = $this->getState('translation.tag');
1483
				$changes_data['filename'] = basename($this->getState('translation.refpath'));
1484
$died = '';
0 ignored issues
show
Unused Code introduced by
$died is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1485
1486
				foreach ($data['text_changes'] as $key => $revised)
1487
				{
1488
					$changes_data['revised'] = "0";
1489
1490
					if ($revised == '1' || $revised == 'true')
1491
					{
1492
						$changes_data['revised'] = "1";
1493
					}
1494
1495
					$changes_data['key'] = $key;
1496
					$changes_data['target_text'] = $data['target_text_changes'][$key];
1497
					$changes_data['source_text'] = $data['source_text_changes'][$key];
1498
1499
					LocaliseHelper::updateRevisedvalue($changes_data);
1500
				}
1501
			}
1502
		}
1503
1504
		// Special case for lib_joomla
1505
		if ($this->getState('translation.filename') == 'lib_joomla')
1506
		{
1507
			$tag = $this->getState('translation.tag');
1508
1509 View Code Duplication
			if (JFolder::exists(JPATH_SITE . "/language/$tag"))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1510
			{
1511
				$this->setState('translation.client', 'site');
1512
				$this->setState('translation.path', JPATH_SITE . "/language/$tag/$tag.lib_joomla.ini");
1513
				$this->saveFile($data);
1514
			}
1515
1516 View Code Duplication
			if (JFolder::exists(JPATH_ADMINISTRATOR . "/language/$tag"))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1517
			{
1518
				$this->setState('translation.client', 'administrator');
1519
				$this->setState('translation.path', JPATH_ADMINISTRATOR . "/language/$tag/$tag.lib_joomla.ini");
1520
				$this->saveFile($data);
1521
			}
1522
		}
1523
		else
1524
		{
1525
			$this->saveFile($data);
1526
		}
1527
1528
		// Bind the rules.
1529
		$table = $this->getTable();
1530
		$table->load($data['id']);
1531
1532
		if (isset($data['rules']))
1533
		{
1534
			$rules = new JAccessRules($data['rules']);
1535
			$table->setRules($rules);
1536
		}
1537
1538
		// Check the data.
1539
		if (!$table->check())
1540
		{
1541
			$this->setError($table->getError());
1542
1543
			return false;
1544
		}
1545
1546
		// Store the data.
1547
		if (!$table->store())
1548
		{
1549
			$this->setError($table->getError());
1550
1551
			return false;
1552
		}
1553
1554
		if ($this->getState('translation.complete') == 1)
1555
		{
1556
			JFactory::getApplication()->enqueueMessage(JText::_('COM_LOCALISE_NOTICE_TRANSLATION_COMPLETE'), 'notice');
1557
		}
1558
		else
1559
		{
1560
			JFactory::getApplication()->enqueueMessage(JText::_('COM_LOCALISE_NOTICE_TRANSLATION_NOT_COMPLETE'), 'notice');
1561
		}
1562
1563
		return true;
1564
	}
1565
}
1566