CodeFile.php 5.28 KB
Newer Older
Qiang Xue committed
1 2 3 4 5 6 7 8 9 10 11
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\gii;

use Yii;
use yii\base\Object;
Alexander Makarov committed
12
use yii\gii\components\DiffRendererHtmlInline;
Qiang Xue committed
13
use yii\helpers\Html;
Qiang Xue committed
14 15

/**
16
 * CodeFile represents a code file to be generated.
Qiang Xue committed
17
 *
18 19 20
 * @property string $relativePath The code file path relative to the application base path. This property is
 * read-only.
 * @property string $type The code file extension (e.g. php, txt). This property is read-only.
21
 *
Qiang Xue committed
22 23 24 25 26
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class CodeFile extends Object
{
27 28 29 30 31 32 33 34 35 36 37 38
    /**
     * The code file is new.
     */
    const OP_CREATE = 'create';
    /**
     * The code file already exists, and the new one may need to overwrite it.
     */
    const OP_OVERWRITE = 'overwrite';
    /**
     * The new code file and the existing one are identical.
     */
    const OP_SKIP = 'skip';
Qiang Xue committed
39

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
    /**
     * @var string an ID that uniquely identifies this code file.
     */
    public $id;
    /**
     * @var string the file path that the new code should be saved to.
     */
    public $path;
    /**
     * @var string the newly generated code content
     */
    public $content;
    /**
     * @var string the operation to be performed. This can be [[OP_NEW]], [[OP_OVERWRITE]] or [[OP_SKIP]].
     */
    public $operation;
Qiang Xue committed
56

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    /**
     * Constructor.
     * @param string $path    the file path that the new code should be saved to.
     * @param string $content the newly generated code content.
     */
    public function __construct($path, $content)
    {
        $this->path = strtr($path, ['/' => DIRECTORY_SEPARATOR, '\\' => DIRECTORY_SEPARATOR]);
        $this->content = $content;
        $this->id = md5($this->path);
        if (is_file($path)) {
            $this->operation = file_get_contents($path) === $content ? self::OP_SKIP : self::OP_OVERWRITE;
        } else {
            $this->operation = self::OP_CREATE;
        }
    }
Qiang Xue committed
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    /**
     * Saves the code into the file specified by [[path]].
     * @return string|boolean the error occurred while saving the code file, or true if no error.
     */
    public function save()
    {
        $module = Yii::$app->controller->module;
        if ($this->operation === self::OP_CREATE) {
            $dir = dirname($this->path);
            if (!is_dir($dir)) {
                $mask = @umask(0);
                $result = @mkdir($dir, $module->newDirMode, true);
                @umask($mask);
                if (!$result) {
                    return "Unable to create the directory '$dir'.";
                }
            }
        }
        if (@file_put_contents($this->path, $this->content) === false) {
            return "Unable to write the file '{$this->path}'.";
        } else {
            $mask = @umask(0);
            @chmod($this->path, $module->newFileMode);
            @umask($mask);
        }
Qiang Xue committed
99

100 101
        return true;
    }
Qiang Xue committed
102

103 104 105 106 107 108 109 110 111 112 113
    /**
     * @return string the code file path relative to the application base path.
     */
    public function getRelativePath()
    {
        if (strpos($this->path, Yii::$app->basePath) === 0) {
            return substr($this->path, strlen(Yii::$app->basePath) + 1);
        } else {
            return $this->path;
        }
    }
Qiang Xue committed
114

115 116 117 118 119 120 121 122 123 124 125
    /**
     * @return string the code file extension (e.g. php, txt)
     */
    public function getType()
    {
        if (($pos = strrpos($this->path, '.')) !== false) {
            return substr($this->path, $pos + 1);
        } else {
            return 'unknown';
        }
    }
Qiang Xue committed
126

127 128 129 130 131 132 133 134 135 136 137 138
    /**
     * Returns preview or false if it cannot be rendered
     *
     * @return boolean|string
     */
    public function preview()
    {
        if (($pos = strrpos($this->path, '.')) !== false) {
            $type = substr($this->path, $pos + 1);
        } else {
            $type = 'unknown';
        }
Qiang Xue committed
139

140 141 142 143 144 145 146 147
        if ($type === 'php') {
            return highlight_string($this->content, true);
        } elseif (!in_array($type, ['jpg', 'gif', 'png', 'exe'])) {
            return nl2br(Html::encode($this->content));
        } else {
            return false;
        }
    }
Alexander Makarov committed
148

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    /**
     * Returns diff or false if it cannot be calculated
     *
     * @return boolean|string
     */
    public function diff()
    {
        $type = strtolower($this->getType());
        if (in_array($type, ['jpg', 'gif', 'png', 'exe'])) {
            return false;
        } elseif ($this->operation === self::OP_OVERWRITE) {
            return $this->renderDiff(file($this->path), $this->content);
        } else {
            return '';
        }
    }
Alexander Makarov committed
165

166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
    /**
     * Renders diff between two sets of lines
     *
     * @param  mixed  $lines1
     * @param  mixed  $lines2
     * @return string
     */
    private function renderDiff($lines1, $lines2)
    {
        if (!is_array($lines1)) {
            $lines1 = explode("\n", $lines1);
        }
        if (!is_array($lines2)) {
            $lines2 = explode("\n", $lines2);
        }
        foreach ($lines1 as $i => $line) {
            $lines1[$i] = rtrim($line, "\r\n");
        }
        foreach ($lines2 as $i => $line) {
            $lines2[$i] = rtrim($line, "\r\n");
        }

        $renderer = new DiffRendererHtmlInline();
        $diff = new \Diff($lines1, $lines2);

        return $diff->render($renderer);
    }
Qiang Xue committed
193
}