Completed
Push — master ( aa18f9...004da0 )
by Andrii
09:23 queued 07:23
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 0
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-2016, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hidev\base;
12
13
use hidev\helpers\Helper;
14
use Yii;
15
16
/**
17
 * A file to be processed with hidev.
18
 *
19
 * @property string $minimalPath path to minimal example file
20
 */
21
class File extends \yii\base\Object
22
{
23
    /**
24
     * @var Goal
25
     */
26
    public $goal;
27
28
    /**
29
     * @var file hanler: renderer and parser
30
     */
31
    protected $_handler;
32
33
    /**
34
     * @var string absolute path
35
     */
36
    protected $_path;
37
38
    /**
39
     * @var string directory
40
     */
41
    protected $_dirname;
42
43
    /**
44
     * @var string name with extension
45
     */
46
    protected $_basename;
47
48
    /**
49
     * @var string name only, without extension
50
     */
51
    protected $_filename;
52
53
    /**
54
     * @var string extension
55
     */
56
    protected $_extension;
57
58
    /**
59
     * @var array file stat
60
     */
61
    protected $_stat;
62
63
    /**
64
     * @var array possible types
65
     */
66
    public $types = [];
67
68
    /**
69
     * @var string type
70
     */
71
    public $type;
72
73
    /**
74
     * @var string template
75
     */
76
    public $template;
77
78
    /**
79
     * @var mixed data
80
     */
81
    protected $data;
82
83
    /**
84
     * @var string path to minimal example file
85
     */
86
    public $minimal;
87
88
    /**
89
     * Create file object.
90
     * @param string|array $path or config
91
     * @return File
92
     */
93 2
    public static function create($path)
94
    {
95 2
        $config = is_array($path) ? $path : compact('path');
96 2
        $config['class'] = get_called_class();
97
98 2
        return Yii::createObject($config);
99
    }
100
101
    /**
102
     * Create plain file (with plain handler).
103
     * @param string $path
104
     * @return File
105
     */
106
    public static function plain($path)
107
    {
108
        return Yii::createObject([
109
            'class' => get_called_class(),
110
            'type'  => 'plain',
111
            'path'  => $path,
112
        ]);
113
    }
114
115 5
    public function getMinimalPath()
116
    {
117 5
        return Yii::getAlias($this->minimal);
118
    }
119
120
    /**
121
     * @var array type to extension correspondance
122
     */
123
    protected static $_extension2type = [
124
        'json'      => 'json',
125
        'yml'       => 'yaml',  /// first one is preferred
126
        'yaml'      => 'yaml',
127
        'xml'       => 'xml',
128
        'xml.dist'  => 'xml',
129
    ];
130
131
    public function getExtensionByType($type)
132
    {
133
        static $type2extension;
134
        if ($type2extension === null) {
135
            foreach (static::$_extension2type as $e => $t) {
136
                if (!$type2extension[$t]) {
137
                    $type2extension[$t] = $e;
138
                }
139
            }
140
        }
141
142
        return $type2extension[$type];
143
    }
144
145 4
    public function getTypeByExtension($extension)
146
    {
147 4
        return isset(static::$_extension2type[$extension]) ? static::$_extension2type[$extension] : null;
148
    }
149
150 5
    public function findType()
151
    {
152 5
        if ($this->type === 'plain') {
153
            return $this->type;
154
        }
155
156 5
        return ($this->goal ? $this->goal->fileType : null) ?: static::getTypeByExtension($this->_extension) ?: 'template';
157
    }
158
159 5
    public function setPath($path)
160
    {
161 5
        $path             = Yii::getAlias($path);
162 5
        $info             = pathinfo($path);
163 5
        $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...
164 5
        $this->_dirname   = isset($info['dirname']) ? $info['dirname'] : null;
165 5
        $this->_basename  = isset($info['basename']) ? $info['basename'] : null;
166 5
        $this->_filename  = isset($info['filename']) ? $info['filename'] : null;
167 5
        $this->_extension = isset($info['extension']) ? $info['extension'] : null;
168 5
        $this->type       = $this->findType();
169 5
    }
170
171 5
    public function getPath()
172
    {
173 5
        return $this->_path;
174
    }
175
176
    public function setBasename($basename)
177
    {
178
        $this->setPath($this->_dirname . '/' . $basename);
179
    }
180
181
    public function getBasename()
182
    {
183
        return $this->_basename;
184
    }
185
186
    public function setDirname($dirname)
187
    {
188
        $this->setPath($dirname . '/' . $this->_basename);
189
    }
190
191 3
    public function getDirname()
192
    {
193 3
        return $this->_dirname;
194
    }
195
196
    public function setFilename($filename)
197
    {
198
        $this->setPath($this->_dirname . '/' . $filename . '.' . $this->_extension);
199
    }
200
201
    public function getFilename()
202
    {
203
        return $this->_filename;
204
    }
205
206
    public function setExtension($extension)
207
    {
208
        $this->setPath($this->_dirname . '/' . $this->_filename . '.' . $extension);
209
    }
210
211
    public function getExtension()
212
    {
213
        return $this->_extension;
214
    }
215
216 5
    public function getCtype()
217
    {
218 5
        return Helper::id2camel($this->type);
219
    }
220
221
    /**
222
     * Save file.
223
     * @param mixed $data
224
     * @return bool true if file was changed
225
     */
226 5
    public function save($data = null)
227
    {
228 5
        if ($data !== null) {
229 5
            $this->data = $data;
230
        }
231
232 5
        return $this->getHandler()->renderPath($this->getPath(), $this->data);
233
    }
234
235
    public function write($content)
236
    {
237
        return $this->getHandler()->write($this->getPath(), $content);
238
    }
239
240 5
    public function load()
241
    {
242 5
        return $this->data = $this->getHandler()->parsePath($this->getPath(), $this->getMinimalPath());
243
    }
244
245
    public function read()
246
    {
247
        return $this->getHandler()->read($this->getPath());
248
    }
249
250
    public function readArray()
251
    {
252
        return $this->getHandler()->readArray($this->getPath());
253
    }
254
255 5
    public function getHandler()
256
    {
257 5
        if (!is_object($this->_handler)) {
258 5
            $this->_handler = Yii::createObject([
259 5
                'class'    => 'hidev\handlers\\' . $this->getCtype() . 'Handler',
260 5
                'template' => $this->template,
261 5
                'goal'     => $this->goal,
262
            ]);
263
        }
264
265 5
        return $this->_handler;
266
    }
267
268
    public static function file_exists($path)
269
    {
270
        return file_exists(Yii::getAlias($path));
271
    }
272
273
    public function exists()
274
    {
275
        return file_exists($this->getPath());
276
    }
277
278
    public function find(array $types = [])
279
    {
280
        if (empty($types)) {
281
            $types = $this->types;
282
        }
283
        foreach ($types as $type) {
284
            foreach (static::$_extension2type as $e => $t) {
285
                if ($t === $type) {
286
                    $this->setExtension($e);
287
                    if ($this->exists()) {
288
                        return true;
289
                    }
290
                }
291
            }
292
        }
293
294
        return false;
295
    }
296
297
    public function get($name)
298
    {
299
        return $this->data[$name];
300
    }
301
302
    public function getStat($field = null)
303
    {
304
        if ($this->_stat === null) {
305
            $this->_stat = stat($this->getPath());
306
        }
307
308
        return is_null($field) ? $this->_stat : $this->_stat[$field];
309
    }
310
311
    public function getUid()
312
    {
313
        return (string) $this->getStat(4);
314
    }
315
316 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...
317
    {
318
        if (!isset($this->_stat['owner'])) {
319
            $this->_stat['owner'] = posix_getpwuid($this->getUid());
320
        }
321
322
        return $this->getStat('owner')['name'];
323
    }
324
325
    public function getGid()
326
    {
327
        return (string) $this->getStat(5);
328
    }
329
330 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...
331
    {
332
        if (!isset($this->_stat['group'])) {
333
            $this->_stat['group'] = posix_getgrgid($this->getGid());
334
        }
335
336
        return $this->getStat('group')['name'];
337
    }
338
339
    public function getPermissions()
340
    {
341
        return static::formatOctal($this->getStat(2));
342
    }
343
344
    public static function formatOctal($value)
345
    {
346
        return substr(sprintf('%o', $value), -4);
347
    }
348
349
    public function chmod($value)
350
    {
351
        $value = is_int($value) ? static::formatOctal($value) : (string) $value;
352
        if ($value === $this->getPermissions()) {
353
            return;
354
        }
355
        $path = $this->getPath();
356
        passthru("chmod $value $path");
357
        Yii::warning("chmod $path '$value'", 'file');
358
    }
359
360
    public function chown($value)
361
    {
362
        $ownergroup = $this->getOwner() . ':' . $this->getGroup();
363
        if (in_array((string) $value, [$ownergroup, $this->getOwner(), $this->getUid()], true)) {
364
            return;
365
        }
366
        $path = $this->getPath();
367
        passthru("chown $value $path");
368
        Yii::warning("chown $path '$value'", 'file');
369
    }
370
371
    public function chgrp($value)
372
    {
373
        if (in_array((string) $value, [$this->getGroup(), $this->getGid()], true)) {
374
            return;
375
        }
376
        $path = $this->getPath();
377
        passthru("chgrp $value $path");
378
        Yii::warning("chgrp $path '$value'", 'file');
379
    }
380
381
    public function symlink($dest)
382
    {
383
        if (file_exists($dest)) {
384
            return true;
385
        }
386
        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...
387
        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...
388
    }
389
}
390