Lang::init()   D
last analyzed

Complexity

Conditions 9
Paths 6

Size

Total Lines 33
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90
Metric Value
dl 0
loc 33
ccs 0
cts 19
cp 0
rs 4.909
cc 9
eloc 16
nc 6
nop 1
crap 90
1
<?php
2
/**
3
 * PHPCI - Continuous Integration for PHP.
4
 *
5
 * @copyright    Copyright 2014, Block 8 Limited.
6
 * @license      https://github.com/Block8/PHPCI/blob/master/LICENSE.md
7
 *
8
 * @link         https://www.phptesting.org/
9
 */
10
11
namespace PHPCI\Helper;
12
13
use b8\Config;
14
15
/**
16
 * Languages Helper Class - Handles loading strings files and the strings within them.
17
 */
18
class Lang
19
{
20
    protected static $language = null;
21
    protected static $strings = array();
22
    protected static $languages = array();
23
24
    /**
25
     * Get a specific string from the language file.
26
     *
27
     * @param string $string
28
     *
29
     * @return mixed|string
30
     */
31 22
    public static function get($string)
32
    {
33 22
        $vars = func_get_args();
34
35 22
        if (array_key_exists($string, self::$strings)) {
36 21
            $vars[0] = self::$strings[$string];
37
38 21
            return call_user_func_array('sprintf', $vars);
39
        }
40
41 1
        return '%%MISSING STRING: '.$string.'%%';
42
    }
43
44
    /**
45
     * Output a specific string from the language file.
46
     */
47
    public static function out()
48
    {
49
        echo call_user_func_array(array('PHPCI\Helper\Lang', 'get'), func_get_args());
50
    }
51
52
    /**
53
     * Get the currently active language.
54
     *
55
     * @return string
56
     */
57
    public static function getLanguage()
58
    {
59
        return self::$language;
60
    }
61
62
    /**
63
     * Try and load a language, and if successful, set it for use throughout the system.
64
     *
65
     * @param $language
66
     *
67
     * @return bool
68
     */
69
    public static function setLanguage($language)
70
    {
71
        if (in_array($language, self::$languages)) {
72
            self::$language = $language;
73
            self::$strings = self::loadLanguage();
0 ignored issues
show
Documentation Bug introduced by
It seems like self::loadLanguage() can be null. However, the property $strings is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
74
75
            return true;
76
        }
77
78
        return false;
79
    }
80
81
    /**
82
     * Return a list of available languages and their names.
83
     *
84
     * @return array
85
     */
86
    public static function getLanguageOptions()
87
    {
88
        $languages = array();
89
90
        foreach (self::$languages as $language) {
91
            $strings = array();
92
            require PHPCI_DIR.'PHPCI/Languages/lang.'.$language.'.php';
93
            $languages[$language] = $strings['language_name'];
94
        }
95
96
        return $languages;
97
    }
98
99
    /**
100
     * Get the strings for the currently active language.
101
     *
102
     * @return string[]
103
     */
104
    public static function getStrings()
105
    {
106
        return self::$strings;
107
    }
108
109
    /**
110
     * Initialise the Language helper, try load the language file for the user's browser or the configured default.
111
     *
112
     * @param Config $config
113
     */
114
    public static function init(Config $config)
0 ignored issues
show
Coding Style introduced by
init uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
init uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
115
    {
116
        self::loadAvailableLanguages();
117
118
        // Try cookies first:
119
        if (isset($_COOKIE) && array_key_exists('phpcilang', $_COOKIE) && self::setLanguage($_COOKIE['phpcilang'])) {
120
            return;
121
        }
122
123
        // Try user language:
124
        if (isset($_SERVER) && array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
125
            $langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
126
127
            foreach ($langs as $lang) {
128
                $parts = explode(';', $lang);
129
                $language = strtolower($parts[0]);
130
131
                if (self::setLanguage($language)) {
132
                    return;
133
                }
134
            }
135
        }
136
137
        // Try the installation default language:
138
        $language = $config->get('phpci.basic.language', null);
139
        if (self::setLanguage($language)) {
140
            return;
141
        }
142
143
        // Fall back to English:
144
        self::$language = 'en';
145
        self::$strings = self::loadLanguage();
0 ignored issues
show
Documentation Bug introduced by
It seems like self::loadLanguage() can be null. However, the property $strings is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
146
    }
147
148
    /**
149
     * Load a specific language file.
150
     *
151
     * @return string[]|null
152
     */
153
    protected static function loadLanguage()
154
    {
155
        $langFile = PHPCI_DIR.'PHPCI/Languages/lang.'.self::$language.'.php';
156
157
        if (!file_exists($langFile)) {
158
            return;
159
        }
160
161
        require $langFile;
162
163
        if (is_null($strings) || !is_array($strings) || !count($strings)) {
0 ignored issues
show
Bug introduced by
The variable $strings does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
164
            return;
165
        }
166
167
        return $strings;
168
    }
169
170
    /**
171
     * Load the names of all available languages.
172
     */
173
    protected static function loadAvailableLanguages()
174
    {
175
        $matches = array();
176
        foreach (glob(PHPCI_DIR.'PHPCI/Languages/lang.*.php') as $file) {
177
            if (preg_match('/lang\.([a-z]{2}\-?[a-z]*)\.php/', $file, $matches)) {
178
                self::$languages[] = $matches[1];
179
            }
180
        }
181
    }
182
183
    /**
184
     * Create a time tag for localization.
185
     *
186
     * See http://momentjs.com/docs/#/displaying/format/ for a list of supported formats.
187
     *
188
     * @param \DateTime $dateTime The dateTime to represent.
189
     * @param string    $format   The moment.js format to use.
190
     *
191
     * @return string The formatted tag.
192
     */
193 2
    public static function formatDateTime(\DateTime $dateTime, $format = 'lll')
194
    {
195 2
        return sprintf(
196 2
            '<time datetime="%s" data-format="%s">%s</time>',
197 2
            $dateTime->format(\DateTime::ISO8601),
198 2
            $format,
199 2
            $dateTime->format(\DateTime::RFC2822)
200 2
        );
201
    }
202
}
203