Completed
Branch master (f07b2a)
by Pierre-Henry
36:36
created

Lang::__construct()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 3
nop 0
dl 0
loc 17
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * @title            Lang Class
4
 * @desc             Loading and management files languages (I18N).
5
 *
6
 * @author           Pierre-Henry Soria <[email protected]>
7
 * @copyright        (c) 2010-2017, Pierre-Henry Soria. All Rights Reserved.
8
 * @license          GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory.
9
 * @package          PH7 / Framework / Translate
10
 */
11
12
namespace PH7\Framework\Translate
13
{
14
 defined('PH7') or exit('Restricted access');
15
16
 use PH7\Framework\Config\Config;
17
 use PH7\Framework\Cookie\Cookie;
18
 use PH7\Framework\Navigation\Browser;
19
 use PH7\Framework\Registry\Registry;
20
21
 class Lang
22
 {
23
     const COOKIE_NAME = 'pHSLang';
24
25
     private $_oConfig, $_sDefaultLang, $_sUserLang, $_sLangName;
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
26
27
     public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_REQUEST 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...
28
     {
29
         $this->_oConfig = Config::getInstance();
30
         $oCookie = new Cookie;
31
32
         // Check a template name has been entered and if it meets the required length.
33
         if (!empty($_REQUEST['l']) && strlen($_REQUEST['l']) == 5) {
34
             $this->_sUserLang = $_REQUEST['l'];
35
             $oCookie->set(static::COOKIE_NAME, $this->_sUserLang, 60*60*48);
36
         } elseif ($oCookie->exists(static::COOKIE_NAME)) {
37
             $this->_sUserLang = $oCookie->get(static::COOKIE_NAME);
38
         } else {
39
             $this->_sUserLang = (new Browser)->getLanguage();
40
         }
41
42
         unset($oCookie);
43
     }
44
45
     /**
46
      * Set the default language name.
47
      *
48
      * @param string $sNewDefLang Prefix of the language.
49
      *
50
      * @return self
51
      */
52
     public function setDefaultLang($sNewDefLang)
53
     {
54
         $this->_sDefaultLang = $sNewDefLang;
55
56
         return $this;
57
     }
58
59
     /**
60
      * Set the user language name.
61
      *
62
      * @param string $sNewUserLang Prefix of the language.
63
      *
64
      * @return self
65
      */
66
     public function setUserLang($sNewUserLang)
67
     {
68
         $this->_sUserLang = $sNewUserLang;
69
70
         return $this;
71
     }
72
73
     /**
74
      * Get the default language name.
75
      *
76
      * @return string The prefix of the language.
77
      */
78
     public function getDefaultLang()
79
     {
80
         return $this->_sDefaultLang;
81
     }
82
83
     /**
84
      * Get the current language name.
85
      *
86
      * @return string The prefix of the language.
87
      */
88
     public function getLang()
89
     {
90
         return $this->_sLangName;
91
     }
92
93
     /**
94
      * Get JavaScript language file.
95
      *
96
      * @param string $sPath The path.
97
      * @param string $sFileName The language name. Default is the constant: 'PH7_LANG_CODE'
98
      *
99
      * @return string Valid file name (with the extension).
100
      *
101
      * @throws Exception If the language file is not found.
102
      */
103
     public static function getJsFile($sPath, $sFileName = PH7_LANG_CODE)
104
     {
105
         if (is_file($sPath . $sFileName . '.js')) {
106
             return $sFileName . '.js';
107
         }
108
109
         if (is_file($sPath . PH7_DEFAULT_LANG_CODE . '.js')) {
110
             return PH7_DEFAULT_LANG_CODE . '.js';
111
         }
112
113
         throw new Exception('Language file \'' . $sPath . PH7_DEFAULT_LANG_CODE . '.js\' not found.');
114
     }
115
116
     /**
117
      * Load the language file.
118
      *
119
      * @param string $sFileName The language filename (e.g., "global").
120
      * @param string $sPath If you want to change the default path (the path to the current module), you can specify the path.
121
      *
122
      * @return self
123
      */
124
     public function load($sFileName, $sPath = null)
125
     {
126
         textdomain($sFileName);
127
         bindtextdomain($sFileName, (empty($sPath) ? Registry::getInstance()->path_module_lang : $sPath) );
0 ignored issues
show
Documentation introduced by
The property path_module_lang does not exist on object<PH7\Framework\Registry\Registry>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
128
         bind_textdomain_codeset($sFileName, PH7_ENCODING);
129
130
         return $this;
131
     }
132
133
     /**
134
      * Loading language files.
135
      *
136
      * @return self
137
      *
138
      * @throws Exception If the language file is not found.
139
      */
140
     public function init()
141
     {
142
         if (!empty($this->_sUserLang) && $this->_oConfig->load(PH7_PATH_APP_LANG . $this->_sUserLang . PH7_DS . PH7_CONFIG . PH7_CONFIG_FILE) && is_file( PH7_PATH_APP_LANG . $this->_sUserLang . '/language.php' ))
143
         {
144
             $this->_sLangName = $this->_sUserLang;
145
             include PH7_PATH_APP_LANG . $this->_sUserLang . '/language.php';
146
             date_default_timezone_set($this->_oConfig->values['language.application']['timezone']);
147
         }
148
         elseif ($this->_oConfig->load(PH7_PATH_APP_LANG . $this->_sDefaultLang . PH7_DS . PH7_CONFIG . PH7_CONFIG_FILE) && is_file( PH7_PATH_APP_LANG . $this->_sDefaultLang . '/language.php' ))
149
         {
150
             $this->_sLangName = $this->_sDefaultLang;
151
             include PH7_PATH_APP_LANG . $this->_sDefaultLang . '/language.php';
152
             date_default_timezone_set($this->_oConfig->values['language.application']['timezone']);
153
         }
154
         elseif ($this->_oConfig->load(PH7_PATH_APP_LANG . PH7_DEFAULT_LANG . PH7_DS . PH7_CONFIG . PH7_CONFIG_FILE) && is_file( PH7_PATH_APP_LANG . PH7_DEFAULT_LANG . '/language.php' ))
155
         {
156
             $this->_sLangName = PH7_DEFAULT_LANG;
157
             include PH7_PATH_APP_LANG . PH7_DEFAULT_LANG . '/language.php';
158
             date_default_timezone_set($this->_oConfig->values['language.application']['timezone']);
159
         }
160
         else
161
         {
162
             throw new Exception('Language file \'' . PH7_PATH_APP_LANG . PH7_DEFAULT_LANG . PH7_DS . PH7_CONFIG . PH7_CONFIG_FILE . '\' and/or Language file \'' . PH7_PATH_APP_LANG . PH7_DEFAULT_LANG . PH7_DS . 'language.php\' not found.');
163
         }
164
165
         // Set the encoding for the specific language set.
166
         $this->_setEncoding();
167
168
         return $this;
169
     }
170
171
    /**
172
     * Set the correct charset to the site.
173
     *
174
     * @return void
175
     */
176
    private function _setEncoding()
177
    {
178
        if (!defined('PH7_ENCODING')) {
179
            define('PH7_ENCODING', $this->_oConfig->values['language']['charset']);
180
        }
181
182
        mb_internal_encoding(PH7_ENCODING);
183
        mb_http_output(PH7_ENCODING);
184
        mb_http_input(PH7_ENCODING);
185
        mb_language('uni');
186
        mb_regex_encoding(PH7_ENCODING);
187
    }
188
 }
189
190
}
191
192
namespace
193
{
194
 use PH7\Framework\Parse\SysVar;
0 ignored issues
show
Coding Style introduced by
USE declarations must go after the first namespace declaration
Loading history...
195
 use PH7\Framework\Registry\Registry;
0 ignored issues
show
Coding Style introduced by
USE declarations must go after the first namespace declaration
Loading history...
196
197
 /**
198
  * Check if GetText PHP extension exists, if not, it'll includes the GetText library.
199
  */
200
 if (!function_exists('gettext')) {
201
     require __DIR__ . '/Adapter/Gettext/gettext.inc.php';
202
 }
203
204
 /**
205
  * Language helper function.
206
  *
207
  * @param string $sVar [, string $... ]
0 ignored issues
show
Bug introduced by
There is no parameter named $sVar. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
208
  *
209
  * @return string Returns the text with gettext function or language in an array (this depends on whether a key language was found in the language table).
210
  */
211
 function t(...$aTokens)
212
 {
213
     $sToken = $aTokens[0];
214
     $sToken = (Registry::getInstance()->lang !== '' && array_key_exists($sToken, Registry::getInstance()->lang) ? Registry::getInstance()->lang[$sToken] : gettext($sToken));
0 ignored issues
show
Documentation introduced by
The property lang does not exist on object<PH7\Framework\Registry\Registry>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
215
216
     for ($i = 1, $iFuncArgs = count($aTokens); $i < $iFuncArgs; $i++) {
217
         $sToken = str_replace('%'. ($i-1) . '%', $aTokens[$i], $sToken);
218
     }
219
220
     return (new SysVar)->parse($sToken);
221
 }
222
223
 /**
224
  * Plurial version of t() function.
225
  *
226
  * @param string $sMsg1 Singular string.
227
  * @param string $sMsg2 Plurial string.
228
  * @param integer $iNumber
229
  *
230
  * @return string Returns the text with ngettext function which is the correct plural form of message identified by msgid1 and msgid2 for count n.
231
  */
232
 function nt($sMsg1, $sMsg2, $iNumber)
233
 {
234
     $sMsg1 = str_replace('%n%', $iNumber, $sMsg1);
235
     $sMsg2 = str_replace('%n%', $iNumber, $sMsg2);
236
237
     return ngettext($sMsg1, $sMsg2, $iNumber);
238
 }
239
}
240