File::getGroup()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
ccs 0
cts 4
cp 0
crap 6
rs 10
1
<?php
2
/**
3
 * Automation tool mixed with code generator for easier continuous development
4
 *
5
 * @link      https://github.com/hiqdev/hidev
6
 * @package   hidev
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2018, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hidev\base;
12
13
use hidev\helpers\FileHelper;
14
use hidev\helpers\Helper;
15
use Yii;
16
17
/**
18
 * A file to be processed with hidev.
19
 *
20
 * @property string $minimalPath path to minimal example file
21
 */
22
class File extends \yii\base\BaseObject
23
{
24
    /**
25
     * @var Goal
0 ignored issues
show
Bug introduced by
The type hidev\base\Goal was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
     */
27
    public $goal;
28
29
    /**
30
     * @var file hanler: renderer and parser
31
     */
32
    protected $_handler;
33
34
    /**
35
     * @var string absolute path
36
     */
37
    protected $_path;
38
39
    /**
40
     * @var string directory
41
     */
42
    protected $_dirname;
43
44
    /**
45
     * @var string name with extension
46
     */
47
    protected $_basename;
48
49
    /**
50
     * @var string name only, without extension
51
     */
52
    protected $_filename;
53
54
    /**
55
     * @var string extension
56
     */
57
    protected $_extension;
58
59
    /**
60
     * @var array file stat
61
     */
62
    protected $_stat;
63
64
    /**
65
     * @var array possible types
66
     */
67
    public $types = [];
68
69
    /**
70
     * @var string type
71
     */
72
    public $type;
73
74
    /**
75
     * @var string template
76
     */
77
    public $template;
78
79
    /**
80
     * @var mixed data
81
     */
82
    protected $data;
83
84
    /**
85
     * @var string path to minimal example file
86
     */
87
    public $minimal;
88
89
    /**
90
     * Create file object.
91
     * @param string|array $path or config
92
     * @return File
93
     */
94
    public static function create($path)
95
    {
96
        $config = is_array($path) ? $path : compact('path');
97
        $config['class'] = get_called_class();
98
99
        return Yii::createObject($config);
100
    }
101
102
    /**
103
     * Create plain file (with plain handler).
104
     * @param string $path
105
     * @return File
106
     */
107
    public static function plain($path)
108
    {
109
        return Yii::createObject([
110
            'class' => get_called_class(),
111
            'type'  => 'plain',
112
            'path'  => $path,
113
        ]);
114
    }
115
116
    public function getMinimalPath()
117
    {
118
        return Yii::getAlias($this->minimal);
119
    }
120
121
    /**
122
     * @var array type to extension correspondance
123
     */
124
    protected static $_extension2type = [
125
        'json'      => 'json',
126
        'yml'       => 'yaml',  /// first one is preferred
127
        'yaml'      => 'yaml',
128
        'xml'       => 'xml',
129
        'xml.dist'  => 'xml',
130
        'gitignore' => 'gitignore',
131
    ];
132
133
    public function getExtensionByType($type)
134
    {
135
        static $type2extension;
136
        if ($type2extension === null) {
137
            foreach (static::$_extension2type as $e => $t) {
138
                if (!$type2extension[$t]) {
139
                    $type2extension[$t] = $e;
140
                }
141
            }
142
        }
143
144
        return $type2extension[$type];
145
    }
146
147 3
    public function getTypeByExtension($extension)
148
    {
149 3
        return isset(static::$_extension2type[$extension]) ? static::$_extension2type[$extension] : null;
150
    }
151
152 3
    public function findType()
153
    {
154 3
        if ($this->type === 'plain') {
155
            return $this->type;
156
        }
157
158 3
        return ($this->goal ? $this->goal->fileType : null) ?: static::getTypeByExtension($this->_extension) ?: 'template';
0 ignored issues
show
Bug Best Practice introduced by
The method hidev\base\File::getTypeByExtension() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

158
        return ($this->goal ? $this->goal->fileType : null) ?: static::/** @scrutinizer ignore-call */ getTypeByExtension($this->_extension) ?: 'template';
Loading history...
159
    }
160
161 3
    public function setPath($path)
162
    {
163 3
        $path             = Yii::getAlias($path);
164 3
        $info             = pathinfo($path);
165 3
        $this->_path      = $path;
0 ignored issues
show
Documentation Bug introduced by
It seems like $path can also be of type boolean. However, the property $_path is declared as type 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...
166 3
        $this->_dirname   = isset($info['dirname']) ? $info['dirname'] : null;
167 3
        $this->_basename  = isset($info['basename']) ? $info['basename'] : null;
168 3
        $this->_filename  = isset($info['filename']) ? $info['filename'] : null;
169 3
        $this->_extension = isset($info['extension']) ? $info['extension'] : null;
170 3
        $this->type       = $this->findType();
171 3
    }
172
173
    public function getAbspath()
174
    {
175
        $path = $this->getPath();
176
        if (strncmp($path, '/', 1)) {
177
            $path = getcwd() . '/' . $path;
178
        }
179
180
        return $path;
181
    }
182
183 3
    public function getPath()
184
    {
185 3
        return $this->_path;
186
    }
187
188
    public function setBasename($basename)
189
    {
190
        $this->setPath($this->_dirname . '/' . $basename);
191
    }
192
193
    public function getBasename()
194
    {
195
        return $this->_basename;
196
    }
197
198
    public function setDirname($dirname)
199
    {
200
        $this->setPath($dirname . '/' . $this->_basename);
201
    }
202
203
    public function getDirname()
204
    {
205
        return $this->_dirname;
206
    }
207
208
    public function setFilename($filename)
209
    {
210
        $this->setPath($this->_dirname . '/' . $filename . '.' . $this->_extension);
211
    }
212
213
    public function getFilename()
214
    {
215
        return $this->_filename;
216
    }
217
218
    public function setExtension($extension)
219
    {
220
        $this->setPath($this->_dirname . '/' . $this->_filename . '.' . $extension);
221
    }
222
223
    public function getExtension()
224
    {
225
        return $this->_extension;
226
    }
227
228 3
    public function getCtype()
229
    {
230 3
        return Helper::id2camel($this->type);
231
    }
232
233
    /**
234
     * Save file.
235
     * @param mixed $data
236
     * @return bool true if file was changed
237
     */
238 3
    public function save($data = null)
239
    {
240 3
        if ($data !== null) {
241 3
            $this->data = $data;
242
        }
243
244 3
        return $this->getHandler()->renderPath($this->getPath(), $this->data);
0 ignored issues
show
Bug introduced by
The method renderPath() does not exist on hidev\base\File. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

244
        return $this->getHandler()->/** @scrutinizer ignore-call */ renderPath($this->getPath(), $this->data);
Loading history...
245
    }
246
247
    public function write($content)
248
    {
249
        return $this->getHandler()->write($this->getPath(), $content);
0 ignored issues
show
Unused Code introduced by
The call to hidev\base\File::write() has too many arguments starting with $content. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

249
        return $this->getHandler()->/** @scrutinizer ignore-call */ write($this->getPath(), $content);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
250
    }
251
252
    public function load()
253
    {
254
        return $this->data = $this->getHandler()->parsePath($this->getPath(), $this->getMinimalPath());
0 ignored issues
show
Bug introduced by
The method parsePath() does not exist on hidev\base\File. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

254
        return $this->data = $this->getHandler()->/** @scrutinizer ignore-call */ parsePath($this->getPath(), $this->getMinimalPath());
Loading history...
255
    }
256
257
    public function read()
258
    {
259
        return $this->getHandler()->read($this->getPath());
0 ignored issues
show
Unused Code introduced by
The call to hidev\base\File::read() has too many arguments starting with $this->getPath(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

259
        return $this->getHandler()->/** @scrutinizer ignore-call */ read($this->getPath());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
260
    }
261
262
    public function readArray()
263
    {
264
        return $this->getHandler()->readArray($this->getPath());
0 ignored issues
show
Unused Code introduced by
The call to hidev\base\File::readArray() has too many arguments starting with $this->getPath(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

264
        return $this->getHandler()->/** @scrutinizer ignore-call */ readArray($this->getPath());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
265
    }
266
267 3
    public function getHandler()
268
    {
269 3
        if (!is_object($this->_handler)) {
270 3
            $this->_handler = Yii::createObject([
271 3
                'class'    => 'hidev\handlers\\' . $this->getCtype() . 'Handler',
272 3
                'template' => $this->template,
273 3
                'goal'     => $this->goal,
274
            ]);
275
        }
276
277 3
        return $this->_handler;
278
    }
279
280
    public static function file_exists($path)
281
    {
282
        return file_exists(Yii::getAlias($path));
283
    }
284
285
    public function exists()
286
    {
287
        return file_exists($this->getPath());
288
    }
289
290
    public function find(array $types = [])
291
    {
292
        if (empty($types)) {
293
            $types = $this->types;
294
        }
295
        foreach ($types as $type) {
296
            foreach (static::$_extension2type as $e => $t) {
297
                if ($t === $type) {
298
                    $this->setExtension($e);
299
                    if ($this->exists()) {
300
                        return true;
301
                    }
302
                }
303
            }
304
        }
305
306
        return false;
307
    }
308
309
    public function get($name)
310
    {
311
        return $this->data[$name];
312
    }
313
314
    public function getStat($field = null)
315
    {
316
        if ($this->_stat === null) {
317
            $this->_stat = stat($this->getPath());
0 ignored issues
show
Documentation Bug introduced by
It seems like stat($this->getPath()) can also be of type false. However, the property $_stat is declared as type array. 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...
318
        }
319
320
        return is_null($field) ? $this->_stat : $this->_stat[$field];
321
    }
322
323
    public function getUid()
324
    {
325
        return (string) $this->getStat(4);
326
    }
327
328
    public function getOwner()
329
    {
330
        if (!isset($this->_stat['owner'])) {
331
            $this->_stat['owner'] = posix_getpwuid($this->getUid());
0 ignored issues
show
Bug introduced by
$this->getUid() of type string is incompatible with the type integer expected by parameter $uid of posix_getpwuid(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

331
            $this->_stat['owner'] = posix_getpwuid(/** @scrutinizer ignore-type */ $this->getUid());
Loading history...
332
        }
333
334
        return $this->getStat('owner')['name'];
335
    }
336
337
    public function getGid()
338
    {
339
        return (string) $this->getStat(5);
340
    }
341
342
    public function getGroup()
343
    {
344
        if (!isset($this->_stat['group'])) {
345
            $this->_stat['group'] = posix_getgrgid($this->getGid());
0 ignored issues
show
Bug introduced by
$this->getGid() of type string is incompatible with the type integer expected by parameter $gid of posix_getgrgid(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

345
            $this->_stat['group'] = posix_getgrgid(/** @scrutinizer ignore-type */ $this->getGid());
Loading history...
346
        }
347
348
        return $this->getStat('group')['name'];
349
    }
350
351
    public function getPermissions()
352
    {
353
        return static::formatOctal($this->getStat(2));
354
    }
355
356
    public static function formatOctal($value)
357
    {
358
        return substr(sprintf('%o', $value), -4);
359
    }
360
361
    public function chmod($value)
362
    {
363
        $value = is_int($value) ? static::formatOctal($value) : (string) $value;
364
        if ($value === $this->getPermissions()) {
365
            return;
366
        }
367
        $path = $this->getPath();
368
        passthru("chmod $value $path");
369
        Yii::warning("chmod $path '$value'", 'file');
370
    }
371
372
    public function chown($value)
373
    {
374
        $ownergroup = $this->getOwner() . ':' . $this->getGroup();
375
        if (in_array((string) $value, [$ownergroup, $this->getOwner(), $this->getUid()], true)) {
376
            return;
377
        }
378
        $path = $this->getPath();
379
        passthru("chown $value $path");
380
        Yii::warning("chown $path '$value'", 'file');
381
    }
382
383
    public function chgrp($value)
384
    {
385
        if (in_array((string) $value, [$this->getGroup(), $this->getGid()], true)) {
386
            return;
387
        }
388
        $path = $this->getPath();
389
        passthru("chgrp $value $path");
390
        Yii::warning("chgrp $path '$value'", 'file');
391
    }
392
393
    public function symlink($dest)
394
    {
395
        if (file_exists($dest)) {
396
            return true;
397
        }
398
        FileHelper::symlink($this->path, $dest);
0 ignored issues
show
Bug Best Practice introduced by
The property path does not exist on hidev\base\File. Since you implemented __get, consider adding a @property annotation.
Loading history...
399
        Yii::warning("Symlinked $this->path $dest", 'file');
400
    }
401
}
402