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

8 9 10
namespace yii\console\controllers;

use yii\console\Controller;
Qiang Xue committed
11
use yii\helpers\FileHelper;
12
use yii\base\Exception;
13

Qiang Xue committed
14
/**
15
 * This command creates an Yii Web application at the specified location.
Qiang Xue committed
16 17
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
18
 * @author Alexander Makarov <sam@rmcreative.ru>
19
 * @since 2.0
Qiang Xue committed
20
 */
21
class AppController extends Controller
Qiang Xue committed
22 23
{
	private $_rootPath;
24 25 26 27
	private $_config;

	/**
	 * @var string custom template path. If specified, templates will be
28
	 * searched there additionally to `framework/console/webapp`.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	 */
	public $templatesPath;

	/**
	 * @var string application type. If not specified default application
	 * skeleton will be used.
	 */
	public $type = 'default';

	public function init()
	{
		parent::init();

		if($this->templatesPath && !is_dir($this->templatesPath)) {
			throw new Exception('--templatesPath "'.$this->templatesPath.'" does not exist or can not be read.');
		}
	}
Qiang Xue committed
46

47 48 49 50 51 52 53
	public function globalOptions()
	{
		return array('templatesPath', 'type');
	}

	public function actionIndex()
	{
54
		$this->forward('help/index', array('-args' => array('app/create')));
55 56
	}

Qiang Xue committed
57
	/**
58 59
	 * Generates Yii application at the path specified via appPath parameter.
	 *
Alexander Makarov committed
60
	 * @param string $path the directory where the new application will be created.
61 62
	 * If the directory does not exist, it will be created. After the application
	 * is created, please make sure the directory has enough permissions.
63 64
	 *
	 * @throws \yii\base\Exception if path specified is not valid
65
	 * @return integer the exit status
Qiang Xue committed
66
	 */
67
	public function actionCreate($path)
Qiang Xue committed
68
	{
69 70 71 72 73 74
		$path = strtr($path, '/\\', DIRECTORY_SEPARATOR);
		if(strpos($path, DIRECTORY_SEPARATOR) === false) {
			$path = '.'.DIRECTORY_SEPARATOR.$path;
		}
		$dir = rtrim(realpath(dirname($path)), '\\/');
		if($dir === false || !is_dir($dir)) {
75
			throw new Exception("The directory '$path' is not valid. Please make sure the parent directory exists.");
76
		}
77

78 79 80 81 82 83
		if(basename($path) === '.') {
			$this->_rootPath = $path = $dir;
		}
		else {
			$this->_rootPath = $path = $dir.DIRECTORY_SEPARATOR.basename($path);
		}
84 85 86 87 88

		if($this->confirm("Create \"$this->type\" application under '$path'?")) {
			$sourceDir = $this->getSourceDir();
			$config = $this->getConfig();

89
			$list = FileHelper::buildFileList($sourceDir, $path);
90 91 92 93 94 95 96 97 98

			if(is_array($config)) {
				foreach($config as $file => $settings) {
					if(isset($settings['handler'])) {
						$list[$file]['callback'] = $settings['handler'];
					}
				}
			}

99
			FileHelper::copyFiles($list);
100 101 102 103 104 105 106 107 108

			if(is_array($config)) {
				foreach($config as $file => $settings) {
					if(isset($settings['permissions'])) {
						@chmod($path.'/'.$file, $settings['permissions']);
					}
				}
			}

Qiang Xue committed
109 110 111 112
			echo "\nYour application has been created successfully under {$path}.\n";
		}
	}

113
	/**
114 115
	 * @throws \yii\base\Exception if source directory wasn't located
	 * @return string
116
	 */
117
	protected function getSourceDir()
Qiang Xue committed
118
	{
119 120 121 122 123 124 125 126 127 128 129 130
		$customSource = realpath($this->templatesPath.'/'.$this->type);
		$defaultSource = realpath($this->getDefaultTemplatesPath().'/'.$this->type);

		if($customSource) {
			return $customSource;
		}
		elseif($defaultSource) {
			return $defaultSource;
		}
		else {
			throw new Exception('Unable to locate the source directory for "'.$this->type.'".');
		}
Qiang Xue committed
131 132
	}

133
	/**
134
	 * @return string default templates path
135
	 */
136
	protected function getDefaultTemplatesPath()
Qiang Xue committed
137
	{
138
		return realpath(__DIR__.'/../webapp');
Qiang Xue committed
139 140
	}

141
	/**
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	 * @return array|null template configuration
	 */
	protected function getConfig()
	{
		if($this->_config===null) {
			$this->_config = require $this->getDefaultTemplatesPath().'/config.php';
			if($this->templatesPath && file_exists($this->templatesPath)) {
				$this->_config = array_merge($this->_config, require $this->templatesPath.'/config.php');
			}
		}
		if(isset($this->_config[$this->type])) {
			return $this->_config[$this->type];
		}
	}

	/**
	 * @param string $source path to source file
	 * @param string $pathTo path to file we want to get relative path for
	 * @param string $varName variable name w/o $ to replace value with relative path for
161
	 *
162
	 * @return string target file contetns
163
	 */
164
	public function replaceRelativePath($source, $pathTo, $varName)
Qiang Xue committed
165
	{
166
		$content = file_get_contents($source);
167 168 169 170 171 172
		$relativeFile = str_replace($this->getSourceDir(), '', $source);

		$relativePath = $this->getRelativePath($pathTo, $this->_rootPath.$relativeFile);
		$relativePath = str_replace('\\', '\\\\', $relativePath);

		return preg_replace('/\$'.$varName.'\s*=(.*?);/', "\$".$varName."=$relativePath;", $content);
Qiang Xue committed
173 174
	}

175
	/**
Qiang Xue committed
176 177
	 * @param string $path1 absolute path
	 * @param string $path2 absolute path
178 179 180 181
	 *
	 * @return string relative path
	 */
	protected function getRelativePath($path1, $path2)
Qiang Xue committed
182
	{
183 184 185 186
		$segs1 = explode(DIRECTORY_SEPARATOR, $path1);
		$segs2 = explode(DIRECTORY_SEPARATOR, $path2);
		$n1 = count($segs1);
		$n2 = count($segs2);
Qiang Xue committed
187

188 189
		for($i=0; $i<$n1 && $i<$n2; ++$i) {
			if($segs1[$i] !== $segs2[$i]) {
Qiang Xue committed
190
				break;
191
			}
Qiang Xue committed
192 193
		}

194
		if($i===0) {
Qiang Xue committed
195
			return "'".$path1."'";
196
		}
Qiang Xue committed
197
		$up='';
198
		for($j=$i;$j<$n2-1;++$j) {
Qiang Xue committed
199
			$up.='/..';
200 201
		}
		for(; $i<$n1-1; ++$i) {
Qiang Xue committed
202
			$up.='/'.$segs1[$i];
203
		}
Qiang Xue committed
204

205
		return '__DIR__.\''.$up.'/'.basename($path1).'\'';
Qiang Xue committed
206 207
	}
}