Completed
Push — master ( fbb4c3...48aefa )
by Andrii
04:08
created

File::formatOctal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
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-2017, 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\Object
23
{
24
    /**
25
     * @var Goal
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';
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);
245
    }
246
247
    public function write($content)
248
    {
249
        return $this->getHandler()->write($this->getPath(), $content);
250
    }
251
252
    public function load()
253
    {
254
        return $this->data = $this->getHandler()->parsePath($this->getPath(), $this->getMinimalPath());
255
    }
256
257
    public function read()
258
    {
259
        return $this->getHandler()->read($this->getPath());
260
    }
261
262
    public function readArray()
263
    {
264
        return $this->getHandler()->readArray($this->getPath());
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());
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 View Code Duplication
    public function getOwner()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
329
    {
330
        if (!isset($this->_stat['owner'])) {
331
            $this->_stat['owner'] = posix_getpwuid($this->getUid());
332
        }
333
334
        return $this->getStat('owner')['name'];
335
    }
336
337
    public function getGid()
338
    {
339
        return (string) $this->getStat(5);
340
    }
341
342 View Code Duplication
    public function getGroup()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
343
    {
344
        if (!isset($this->_stat['group'])) {
345
            $this->_stat['group'] = posix_getgrgid($this->getGid());
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
Documentation introduced by
The property path does not exist on object<hidev\base\File>. 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...
399
        Yii::warning("Symlinked $this->path $dest", 'file');
0 ignored issues
show
Documentation introduced by
The property path does not exist on object<hidev\base\File>. 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...
400
    }
401
}
402