Completed
Pull Request — master (#499)
by Richard
10:41
created

XoopsBaseConfig::getInstance()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 4
nop 1
dl 0
loc 13
rs 8.8571
c 0
b 0
f 0
ccs 0
cts 7
cp 0
crap 30
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
 */
11
12
use Xmf\Yaml;
13
14
/**
15
 * XoopsBaseConfig holds the base XOOPS configs needed to locate key paths and
16
 * enable database access
17
 *
18
 * @category  XoopsBaseConfig
19
 * @package   XoopsBaseConfig
20
 * @author    Richard Griffith <[email protected]>
21
 * @copyright 2015 XOOPS Project (http://xoops.org)
22
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
23
 * @link      http://xoops.org
24
 */
25
class XoopsBaseConfig
26
{
27
    /**
28
     * @var string[] $configs
29
     */
30
    private static $configs = array();
31
32
    /**
33
     * __construct
34
     * @param string|string[] $config fully qualified name of configuration file
35
     *                                or configuration array
36
     * @throws Exception
37
     */
38
    final private function __construct($config)
0 ignored issues
show
introduced by
Instead of declaring the constructor as final, maybe you should declare the entire class as final.
Loading history...
39
    {
40
        if (!class_exists('XoopsLoad', false)) {
41
            include __DIR__ . '/xoopsload.php';
42
        }
43
        if (is_string($config)) {
44
            $yamlString = file_get_contents($config);
45
            if ($yamlString === false) {
46
                throw new \Exception('XoopsBaseConfig failed to load configuration.');
47
            }
48
            $loaderPath = $this->extractLibPath($yamlString) . '/vendor/autoload.php';
49
            if (file_exists($loaderPath)) {
50
                include_once $loaderPath;
51
            }
52
            self::$configs = Yaml::loadWrapped($yamlString);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Xmf\Yaml::loadWrapped($yamlString) can also be of type boolean. However, the property $configs is declared as type array<integer,string>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
53
            \XoopsLoad::startAutoloader(self::$configs['lib-path']);
54
        } elseif (is_array($config)) {
55
            self::$configs = $config;
56
            \XoopsLoad::startAutoloader(self::$configs['lib-path']);
57
        }
58
        if (!isset(self::$configs['lib-path'])) {
59
            throw new \Exception('XoopsBaseConfig lib-path not defined.');
60
            return;
0 ignored issues
show
Unused Code introduced by
return; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
61
        }
62
        \XoopsLoad::startAutoloader(self::$configs['lib-path']);
63
    }
64
65
    /**
66
     * Allow one instance only!
67
     *
68
     * @param string|string[] $config fully qualified name of configuration file
69
     *                                or configuration array
70
     *
71
     * @return XoopsBaseConfig instance
72
     * @throws Exception
73
     */
74
    final public static function getInstance($config = '')
75
    {
76
        static $instance = false;
77
78
        if (!$instance && !empty($config)) {
79
            $instance = new \XoopsBaseConfig($config);
80
        }
81
82
        if ($instance === false || empty(self::$configs)) {
83
            throw new \Exception('XoopsBaseConfig failed.');
84
        }
85
        return $instance;
86
    }
87
88
    /**
89
     * extractLibPath - solve a which comes first, chicken or egg type problem
90
     *
91
     * The yaml file we can load has the path we need to set up the autoloader we need
92
     * to reach our yaml library. We solve this by looking through the raw yaml file
93
     * contents to locate our data. This works only because there is a unique key that
94
     * should not be duplicated in a limited and known data set.
95
     *
96
     * Not pretty, but this way we get full access to xoops from a single known path.
97
     *
98
     * @param string $filecontents contents of the yaml configuration file
99
     *
100
     * @return string the extracted lib-path value
101
     */
102
    final private function extractLibPath($filecontents)
103
    {
104
        $match = array();
105
        $matched = preg_match('/[.\v]*^lib-path\h*\:\h*[\']?([^\'\v]*)[\']?\h*$[.\v]*/m', $filecontents, $match);
106
107
        return $matched ? trim($match[1]) : '';
108
    }
109
110
    /**
111
     * Retrieve an attribute value.
112
     *
113
     * @param string $name name of an attribute
114
     *
115
     * @return mixed value of the attribute, or null if not set.
116
     */
117 373
    final public static function get($name)
118
    {
119 373
        if (isset(self::$configs[$name])) {
120 373
            return self::$configs[$name];
121
        }
122
        //trigger_error('variable : '.$name.' not found!', E_USER_ERROR);
123
        return null;
124
    }
125
126
    /**
127
     * Verify an attribute is defined.
128
     *
129
     * @param string $name name of an attribute
130
     *
131
     * @return boolean true if attribute is defined, otherwise false.
132
     */
133
    final public static function has($name)
134
    {
135
        return isset(self::$configs[$name]);
136
    }
137
138
    /**
139
     * Get a copy of all base configurations
140
     *
141
     * @return array of of all attributes
142
     */
143
    final public function getAll()
144
    {
145
        return self::$configs;
146
    }
147
148
    /**
149
     * Establish backward compatibility defines
150
     *
151
     * @return void
152
     */
153
    final public static function establishBCDefines()
154
    {
155
        if (defined('XOOPS_ROOT_PATH')) {
156
            return;
157
        }
158
159
        // Physical path to the XOOPS documents (served) directory WITHOUT trailing slash
160
        define('XOOPS_ROOT_PATH', self::get('root-path'));
161
162
        // For forward compatibility
163
        // Physical path to the XOOPS library directory WITHOUT trailing slash
164
        define('XOOPS_PATH', self::get('lib-path'));
165
        // Physical path to the XOOPS datafiles (writable) directory WITHOUT trailing slash
166
        define('XOOPS_VAR_PATH', self::get('var-path'));
167
        // Alias of XOOPS_PATH, for compatibility, temporary solution
168
        define("XOOPS_TRUST_PATH", self::get('trust-path'));
169
170
        // URL Association for SSL and Protocol Compatibility
171
        define('XOOPS_PROT', self::get('prot'));
172
173
        // XOOPS Virtual Path (URL)
174
        // Virtual path to your main XOOPS directory WITHOUT trailing slash
175
        // Example: define('XOOPS_URL', 'http://localhost/xoopscore');
176
        define('XOOPS_URL', self::get('url'));
177
178
        // Secure file
179
        // require XOOPS_VAR_PATH . '/data/secure.php';
180
181
        // Database
182
        // Choose the database to be used
183
        define('XOOPS_DB_TYPE', self::get('db-type'));
184
185
        // Set the database charset if applicable
186
        define("XOOPS_DB_CHARSET", self::get('db-charset'));
187
188
        // Table Prefix
189
        // This prefix will be added to all new tables created to avoid name conflict in the database.
190
        define('XOOPS_DB_PREFIX', self::get('db-prefix'));
191
192
        // Database Hostname
193
        // Hostname of the database server. If you are unsure, "localhost" works in most cases.
194
        define('XOOPS_DB_HOST', self::get('db-host'));
195
196
        // Database Username
197
        // Your database user account on the host
198
        define('XOOPS_DB_USER', self::get('db-user'));
199
200
        // Database Password
201
        // Password for your database user account
202
        define('XOOPS_DB_PASS', self::get('db-pass'));
203
204
        // Database Name
205
        // The name of database on the host.
206
        define('XOOPS_DB_NAME', self::get('db-name'));
207
208
        // persistent connection is no longer supported
209
        define("XOOPS_DB_PCONNECT", self::get('db-pconnect'));
210
211
        // Serialized connection parameter
212
        // This is built by the installer and includes all connection parameters
213
        define('XOOPS_DB_PARAMETERS', serialize(self::get('db-parameters')));
214
215
        define('XOOPS_UPLOAD_PATH', self::get('uploads-path'));
216
        define('XOOPS_UPLOAD_URL', self::get('uploads-url'));
217
    }
218
219
    /**
220
     * Create a working environment from traditional mainfile environment
221
     *
222
     * For the early phases in the installer, these may not be defined. Until it
223
     * is converted we try and do the best we can without errors
224
     *
225
     * @return void
226
     */
227
    final public static function bootstrapTransition()
0 ignored issues
show
Coding Style introduced by
bootstrapTransition 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...
228
    {
229
        $path = self::defineDefault('XOOPS_ROOT_PATH', basename(__DIR__));
230
        $url = (defined('XOOPS_URL')) ?
231
            XOOPS_URL :
232
            ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === "on") ? 'https://' : 'http://')
233
            . $_SERVER['SERVER_NAME']
234
            . (($_SERVER['SERVER_PORT'] != '80') ? ':' . $_SERVER['SERVER_PORT'] : '');
235
236
        $parts = parse_url($url . '/');
237
        $host = isset($parts['host']) ? $parts['host'] : $_SERVER['SERVER_NAME'];
238
        $host = ($host==='localhost') ? '' : $host;
239
        $urlpath = isset($parts['path']) ? $parts['path'] : '/';
240
241
        $libpath = self::defineDefault('XOOPS_PATH');
242
        $varpath = self::defineDefault('XOOPS_VAR_PATH');
243
244
        $configs = array(
245
            'root-path' => $path,
246
            'lib-path' => $libpath,
247
            'var-path' => $varpath,
248
            'trust-path' => $libpath,
249
            'url' => $url,
250
            'prot' => self::defineDefault('XOOPS_PROT'),
251
            'asset-path' => $path . '/assets',
252
            'asset-url' => $url . '/assets',
253
            'themes-path' => $path .'/themes',
254
            'themes-url' => $url . '/themes',
255
            'adminthemes-path' => $path . '/modules/system/themes',
256
            'adminthemes-url' => $url . '/modules/system/themes',
257
            'media-path' => $path . '/media',
258
            'media-url' => $url . '/media',
259
            'uploads-path' => $path . '/uploads',
260
            'uploads-url' => $url . '/uploads',
261
            'cookie-domain' => $host,
262
            'cookie-path' => $urlpath,
263
            'smarty-cache' => $varpath . '/caches/smarty_cache',
264
            'smarty-compile' => $varpath . '/caches/smarty_compile',
265
            'smarty-xoops-plugins' => $libpath . '/smarty/xoops_plugins',
266
            'db-type' => self::defineDefault('XOOPS_DB_TYPE'),
267
            'db-charset' => 'utf8',
268
            'db-prefix' => self::defineDefault('XOOPS_DB_PREFIX'),
269
            'db-host' => self::defineDefault('XOOPS_DB_HOST'),
270
            'db-user' => self::defineDefault('XOOPS_DB_USER'),
271
            'db-pass' => self::defineDefault('XOOPS_DB_PASS'),
272
            'db-name' => self::defineDefault('XOOPS_DB_NAME'),
273
            'db-pconnect' => 0,
274
            'db-parameters' => defined('XOOPS_DB_PARAMETERS') ? unserialize(XOOPS_DB_PARAMETERS) : array(),
275
        );
276
        self::getInstance($configs);
277
    }
278
279
    /**
280
     * defineDefault - return a constant if it is defined, or a default value if not.
281
     * If no default is specified, the define name will be used if needed.
282
     *
283
     * @param string      $define  a define constant name
284
     * @param string|null $default default value to return if $define is not defined
285
     *
286
     * @return string value of define or default
287
     */
288
    private static function defineDefault($define, $default = null)
289
    {
290
        $default = ($default === null) ? $define : $default;
291
        $return = defined($define) ? constant($define) : $default;
292
        return $return;
293
    }
294
}
295