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.
Completed
Pull Request — develop (#322)
by
unknown
01:52
created

ArrayHelper::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Part of the Joomla Framework Utilities Package
4
 *
5
 * @copyright  Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
6
 * @license    GNU General Public License version 2 or later; see LICENSE
7
 */
8
9
namespace Joomla\Utilities;
10
11
use Joomla\String\StringHelper;
12
13
/**
14
 * ArrayHelper is an array utility class for doing all sorts of odds and ends with arrays.
15
 *
16
 * @since  1.0
17
 */
18
final class ArrayHelper
19
{
20
	/**
21
	 * Private constructor to prevent instantiation of this class
22
	 *
23
	 * @since   1.0
24
	 */
25
	private function __construct()
26
	{
27
	}
28
29
	/**
30
	 * Function to convert array to integer values
31
	 *
32
	 * @param   array  $array    The source array to convert
33
	 * @param   mixed  $default  A default value (int|array) to assign if $array is not an array
34
	 *
35
	 * @return  array
36
	 *
37
	 * @since   1.0
38
	 */
39
	public static function toInteger($array, $default = null)
40
	{
41
		if (is_array($array))
42
		{
43
			return array_map('intval', $array);
44
		}
45
46
		if ($default === null)
47
		{
48
			return array();
49
		}
50
51
		if (is_array($default))
52
		{
53
			return static::toInteger($default, null);
54
		}
55
56
		return array((int) $default);
57
	}
58
59
	/**
60
	 * Utility function to map an array to a stdClass object.
61
	 *
62
	 * @param   array    $array      The array to map.
63
	 * @param   string   $class      Name of the class to create
64
	 * @param   boolean  $recursive  Convert also any array inside the main array
65
	 *
66
	 * @return  object
67
	 *
68
	 * @since   1.0
69
	 */
70
	public static function toObject(array $array, $class = 'stdClass', $recursive = true)
71
	{
72
		$obj = new $class;
73
74
		foreach ($array as $k => $v)
75
		{
76
			if ($recursive && is_array($v))
77
			{
78
				$obj->$k = static::toObject($v, $class);
79
			}
80
			else
81
			{
82
				$obj->$k = $v;
83
			}
84
		}
85
86
		return $obj;
87
	}
88
89
	/**
90
	 * Utility function to map an array to a string.
91
	 *
92
	 * @param   array    $array         The array to map.
93
	 * @param   string   $inner_glue    The glue (optional, defaults to '=') between the key and the value.
94
	 * @param   string   $outer_glue    The glue (optional, defaults to ' ') between array elements.
95
	 * @param   boolean  $keepOuterKey  True if final key should be kept.
96
	 *
97
	 * @return  string
98
	 *
99
	 * @since   1.0
100
	 */
101
	public static function toString(array $array, $inner_glue = '=', $outer_glue = ' ', $keepOuterKey = false)
102
	{
103
		$output = array();
104
105
		foreach ($array as $key => $item)
106
		{
107
			if (is_array($item))
108
			{
109
				if ($keepOuterKey)
110
				{
111
					$output[] = $key;
112
				}
113
114
				// This is value is an array, go and do it again!
115
				$output[] = static::toString($item, $inner_glue, $outer_glue, $keepOuterKey);
116
			}
117
			else
118
			{
119
				$output[] = $key . $inner_glue . '"' . $item . '"';
120
			}
121
		}
122
123
		return implode($outer_glue, $output);
124
	}
125
126
	/**
127
	 * Utility function to map an object to an array
128
	 *
129
	 * @param   object   $p_obj    The source object
130
	 * @param   boolean  $recurse  True to recurse through multi-level objects
131
	 * @param   string   $regex    An optional regular expression to match on field names
132
	 *
133
	 * @return  array
134
	 *
135
	 * @since   1.0
136
	 */
137
	public static function fromObject($p_obj, $recurse = true, $regex = null)
138
	{
139
		if (is_object($p_obj) || is_array($p_obj))
140
		{
141
			return self::arrayFromObject($p_obj, $recurse, $regex);
142
		}
143
144
		return array();
145
	}
146
147
	/**
148
	 * Utility function to map an object or array to an array
149
	 *
150
	 * @param   mixed    $item     The source object or array
151
	 * @param   boolean  $recurse  True to recurse through multi-level objects
152
	 * @param   string   $regex    An optional regular expression to match on field names
153
	 *
154
	 * @return  array
155
	 *
156
	 * @since   1.0
157
	 */
158
	private static function arrayFromObject($item, $recurse, $regex)
159
	{
160
		if (is_object($item))
161
		{
162
			$result = array();
163
164
			foreach (get_object_vars($item) as $k => $v)
165
			{
166 View Code Duplication
				if (!$regex || preg_match($regex, $k))
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...
167
				{
168
					if ($recurse)
169
					{
170
						$result[$k] = self::arrayFromObject($v, $recurse, $regex);
171
					}
172
					else
173
					{
174
						$result[$k] = $v;
175
					}
176
				}
177
			}
178
179
			return $result;
180
		}
181
182 View Code Duplication
		if (is_array($item))
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...
183
		{
184
			$result = array();
185
186
			foreach ($item as $k => $v)
187
			{
188
				$result[$k] = self::arrayFromObject($v, $recurse, $regex);
189
			}
190
191
			return $result;
192
		}
193
194
		return $item;
195
	}
196
197
	/**
198
	 * Extracts a column from an array of arrays or objects
199
	 *
200
	 * @param   array   $array     The source array
201
	 * @param   string  $valueCol  The index of the column or name of object property to be used as value
202
	 *                             It may also be NULL to return complete arrays or objects (this is
203
	 *                             useful together with <var>$keyCol</var> to reindex the array).
204
	 * @param   string  $keyCol    The index of the column or name of object property to be used as key
205
	 *
206
	 * @return  array  Column of values from the source array
207
	 *
208
	 * @since   1.0
209
	 * @see     http://php.net/manual/en/language.types.array.php
210
	 * @see     http://php.net/manual/en/function.array-column.php
211
	 */
212
	public static function getColumn(array $array, $valueCol, $keyCol = null)
213
	{
214
		$result = array();
215
216
		foreach ($array as $item)
217
		{
218
			// Convert object to array
219
			$subject = is_object($item) ? static::fromObject($item) : $item;
220
221
			/*
222
			 * We process arrays (and objects already converted to array)
223
			 * Only if the value column (if required) exists in this item
224
			 */
225
			if (is_array($subject) && (!isset($valueCol) || isset($subject[$valueCol])))
226
			{
227
				// Use whole $item if valueCol is null, else use the value column.
228
				$value = isset($valueCol) ? $subject[$valueCol] : $item;
229
230
				// Array keys can only be integer or string. Casting will occur as per the PHP Manual.
231
				if (isset($keyCol) && isset($subject[$keyCol]) && is_scalar($subject[$keyCol]))
232
				{
233
					$key          = $subject[$keyCol];
234
					$result[$key] = $value;
235
				}
236
				else
237
				{
238
					$result[] = $value;
239
				}
240
			}
241
		}
242
243
		return $result;
244
	}
245
246
	/**
247
	 * Utility function to return a value from a named array or a specified default
248
	 *
249
	 * @param   array|\ArrayAccess  $array    A named array or object that implements ArrayAccess
250
	 * @param   string              $name     The key to search for
251
	 * @param   mixed               $default  The default value to give if no key found
252
	 * @param   string              $type     Return type for the variable (INT, FLOAT, STRING, WORD, BOOLEAN, ARRAY)
253
	 *
254
	 * @return  mixed
255
	 *
256
	 * @since   1.0
257
	 * @throws  \InvalidArgumentException
258
	 */
259
	public static function getValue($array, $name, $default = null, $type = '')
260
	{
261
		if (!is_array($array) && !($array instanceof \ArrayAccess))
262
		{
263
			throw new \InvalidArgumentException('The object must be an array or an object that implements ArrayAccess');
264
		}
265
266
		$result = null;
267
268
		if (isset($array[$name]))
269
		{
270
			$result = $array[$name];
271
		}
272
273
		// Handle the default case
274
		if (is_null($result))
275
		{
276
			$result = $default;
277
		}
278
279
		// Handle the type constraint
280
		switch (strtoupper($type))
281
		{
282
			case 'INT':
283
			case 'INTEGER':
284
				// Only use the first integer value
285
				@preg_match('/-?[0-9]+/', $result, $matches);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
286
				$result = @(int) $matches[0];
287
				break;
288
289
			case 'FLOAT':
290
			case 'DOUBLE':
291
				// Only use the first floating point value
292
				@preg_match('/-?[0-9]+(\.[0-9]+)?/', $result, $matches);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
293
				$result = @(float) $matches[0];
294
				break;
295
296
			case 'BOOL':
297
			case 'BOOLEAN':
298
				$result = (bool) $result;
299
				break;
300
301
			case 'ARRAY':
302
				if (!is_array($result))
303
				{
304
					$result = array($result);
305
				}
306
				break;
307
308
			case 'STRING':
309
				$result = (string) $result;
310
				break;
311
312
			case 'WORD':
313
				$result = (string) preg_replace('#\W#', '', $result);
314
				break;
315
316
			case 'NONE':
317
			default:
318
				// No casting necessary
319
				break;
320
		}
321
322
		return $result;
323
	}
324
325
	/**
326
	 * Takes an associative array of arrays and inverts the array keys to values using the array values as keys.
327
	 *
328
	 * Example:
329
	 * $input = array(
330
	 *     'New' => array('1000', '1500', '1750'),
331
	 *     'Used' => array('3000', '4000', '5000', '6000')
332
	 * );
333
	 * $output = ArrayHelper::invert($input);
334
	 *
335
	 * Output would be equal to:
336
	 * $output = array(
337
	 *     '1000' => 'New',
338
	 *     '1500' => 'New',
339
	 *     '1750' => 'New',
340
	 *     '3000' => 'Used',
341
	 *     '4000' => 'Used',
342
	 *     '5000' => 'Used',
343
	 *     '6000' => 'Used'
344
	 * );
345
	 *
346
	 * @param   array  $array  The source array.
347
	 *
348
	 * @return  array
349
	 *
350
	 * @since   1.0
351
	 */
352
	public static function invert(array $array)
353
	{
354
		$return = array();
355
356
		foreach ($array as $base => $values)
357
		{
358
			if (!is_array($values))
359
			{
360
				continue;
361
			}
362
363
			foreach ($values as $key)
364
			{
365
				// If the key isn't scalar then ignore it.
366
				if (is_scalar($key))
367
				{
368
					$return[$key] = $base;
369
				}
370
			}
371
		}
372
373
		return $return;
374
	}
375
376
	/**
377
	 * Method to determine if an array is an associative array.
378
	 *
379
	 * @param   array  $array  An array to test.
380
	 *
381
	 * @return  boolean
382
	 *
383
	 * @since   1.0
384
	 */
385
	public static function isAssociative($array)
386
	{
387
		if (is_array($array))
388
		{
389
			foreach (array_keys($array) as $k => $v)
390
			{
391
				if ($k !== $v)
392
				{
393
					return true;
394
				}
395
			}
396
		}
397
398
		return false;
399
	}
400
401
	/**
402
	 * Pivots an array to create a reverse lookup of an array of scalars, arrays or objects.
403
	 *
404
	 * @param   array   $source  The source array.
405
	 * @param   string  $key     Where the elements of the source array are objects or arrays, the key to pivot on.
406
	 *
407
	 * @return  array  An array of arrays pivoted either on the value of the keys, or an individual key of an object or array.
408
	 *
409
	 * @since   1.0
410
	 */
411
	public static function pivot(array $source, $key = null)
412
	{
413
		$result  = array();
414
		$counter = array();
415
416
		foreach ($source as $index => $value)
417
		{
418
			// Determine the name of the pivot key, and its value.
419
			if (is_array($value))
420
			{
421
				// If the key does not exist, ignore it.
422
				if (!isset($value[$key]))
423
				{
424
					continue;
425
				}
426
427
				$resultKey   = $value[$key];
428
				$resultValue = $source[$index];
429
			}
430
			elseif (is_object($value))
431
			{
432
				// If the key does not exist, ignore it.
433
				if (!isset($value->$key))
434
				{
435
					continue;
436
				}
437
438
				$resultKey   = $value->$key;
439
				$resultValue = $source[$index];
440
			}
441
			else
442
			{
443
				// Just a scalar value.
444
				$resultKey   = $value;
445
				$resultValue = $index;
446
			}
447
448
			// The counter tracks how many times a key has been used.
449
			if (empty($counter[$resultKey]))
450
			{
451
				// The first time around we just assign the value to the key.
452
				$result[$resultKey] = $resultValue;
453
				$counter[$resultKey] = 1;
454
			}
455
			elseif ($counter[$resultKey] == 1)
456
			{
457
				// If there is a second time, we convert the value into an array.
458
				$result[$resultKey] = array(
459
					$result[$resultKey],
460
					$resultValue,
461
				);
462
				$counter[$resultKey]++;
463
			}
464
			else
465
			{
466
				// After the second time, no need to track any more. Just append to the existing array.
467
				$result[$resultKey][] = $resultValue;
468
			}
469
		}
470
471
		unset($counter);
472
473
		return $result;
474
	}
475
476
	/**
477
	 * Utility function to sort an array of objects on a given field
478
	 *
479
	 * @param   array  $a              An array of objects
480
	 * @param   mixed  $k              The key (string) or an array of keys to sort on
481
	 * @param   mixed  $direction      Direction (integer) or an array of direction to sort in [1 = Ascending] [-1 = Descending]
482
	 * @param   mixed  $caseSensitive  Boolean or array of booleans to let sort occur case sensitive or insensitive
483
	 * @param   mixed  $locale         Boolean or array of booleans to let sort occur using the locale language or not
484
	 *
485
	 * @return  array
486
	 *
487
	 * @since   1.0
488
	 */
489
	public static function sortObjects(array $a, $k, $direction = 1, $caseSensitive = true, $locale = false)
490
	{
491
		if (!is_array($locale) || !is_array($locale[0]))
492
		{
493
			$locale = array($locale);
494
		}
495
496
		$sortCase      = (array) $caseSensitive;
497
		$sortDirection = (array) $direction;
498
		$key           = (array) $k;
499
		$sortLocale    = $locale;
500
501
		usort(
502
			$a, function ($a, $b) use ($sortCase, $sortDirection, $key, $sortLocale)
503
			{
504
				for ($i = 0, $count = count($key); $i < $count; $i++)
505
				{
506
					if (isset($sortDirection[$i]))
507
					{
508
						$direction = $sortDirection[$i];
509
					}
510
511
					if (isset($sortCase[$i]))
512
					{
513
						$caseSensitive = $sortCase[$i];
514
					}
515
516
					if (isset($sortLocale[$i]))
517
					{
518
						$locale = $sortLocale[$i];
519
					}
520
521
					$va = $a->{$key[$i]};
522
					$vb = $b->{$key[$i]};
523
524
					if ((is_bool($va) || is_numeric($va)) && (is_bool($vb) || is_numeric($vb)))
525
					{
526
						$cmp = $va - $vb;
527
					}
528
					elseif ($caseSensitive)
0 ignored issues
show
Bug introduced by
The variable $caseSensitive 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...
529
					{
530
						$cmp = StringHelper::strcmp($va, $vb, $locale);
0 ignored issues
show
Bug introduced by
The variable $locale 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...
531
					}
532
					else
533
					{
534
						$cmp = StringHelper::strcasecmp($va, $vb, $locale);
535
					}
536
537
					if ($cmp > 0)
538
					{
539
						return $direction;
0 ignored issues
show
Bug introduced by
The variable $direction 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...
540
					}
541
542
					if ($cmp < 0)
543
					{
544
						return -$direction;
545
					}
546
				}
547
548
				return 0;
549
			}
550
		);
551
552
		return $a;
553
	}
554
555
	/**
556
	 * Multidimensional array safe unique test
557
	 *
558
	 * @param   array  $array  The array to make unique.
559
	 *
560
	 * @return  array
561
	 *
562
	 * @see     http://php.net/manual/en/function.array-unique.php
563
	 * @since   1.0
564
	 */
565
	public static function arrayUnique(array $array)
566
	{
567
		$array = array_map('serialize', $array);
568
		$array = array_unique($array);
569
		$array = array_map('unserialize', $array);
570
571
		return $array;
572
	}
573
574
	/**
575
	 * An improved array_search that allows for partial matching of strings values in associative arrays.
576
	 *
577
	 * @param   string   $needle         The text to search for within the array.
578
	 * @param   array    $haystack       Associative array to search in to find $needle.
579
	 * @param   boolean  $caseSensitive  True to search case sensitive, false otherwise.
580
	 *
581
	 * @return  mixed    Returns the matching array $key if found, otherwise false.
582
	 *
583
	 * @since   1.0
584
	 */
585
	public static function arraySearch($needle, array $haystack, $caseSensitive = true)
586
	{
587
		foreach ($haystack as $key => $value)
588
		{
589
			$searchFunc = ($caseSensitive) ? 'strpos' : 'stripos';
590
591
			if ($searchFunc($value, $needle) === 0)
592
			{
593
				return $key;
594
			}
595
		}
596
597
		return false;
598
	}
599
600
	/**
601
	 * Method to recursively convert data to a one dimension array.
602
	 *
603
	 * @param   array|object  $array      The array or object to convert.
604
	 * @param   string        $separator  The key separator.
605
	 * @param   string        $prefix     Last level key prefix.
606
	 *
607
	 * @return  array
608
	 *
609
	 * @since   1.3.0
610
	 */
611
	public static function flatten($array, $separator = '.', $prefix = '')
612
	{
613
		if ($array instanceof \Traversable)
614
		{
615
			$array = iterator_to_array($array);
616
		}
617
		elseif (is_object($array))
618
		{
619
			$array = get_object_vars($array);
620
		}
621
622
		foreach ($array as $k => $v)
623
		{
624
			$key = $prefix ? $prefix . $separator . $k : $k;
625
626
			if (is_object($v) || is_array($v))
627
			{
628
				$array = array_merge($array, static::flatten($v, $separator, $key));
629
			}
630
			else
631
			{
632
				$array[$key] = $v;
633
			}
634
		}
635
636
		return $array;
637
	}
638
}
639