args[0])) {
$project = $this->args[0];
} else {
$appContents = array_diff(scandir(APP), array('.', '..'));
if (empty($appContents)) {
$suggestedPath = rtrim(APP, DS);
} else {
$suggestedPath = APP . 'MyApp';
}
}
while (!$project) {
$prompt = __d('cake_console', 'What is the path to the project you want to bake?');
$project = $this->in($prompt, null, $suggestedPath);
}
$namespace = basename($project);
if (!preg_match('/^\w[\w\d_]+$/', $namespace)) {
$this->err(__d('cake_console', 'Project Name/Namespace needs to start with a letter and can only contain letters, digits and underscore'));
$this->args = array();
return $this->execute();
}
if ($project && !Folder::isAbsolute($project) && isset($_SERVER['PWD'])) {
$project = $_SERVER['PWD'] . DS . $project;
}
$response = false;
while (!$response && is_dir($project) === true && file_exists($project . 'Config' . 'boostrap.php')) {
$prompt = __d('cake_console', 'A project already exists in this location: %s Overwrite?', $project);
$response = $this->in($prompt, array('y', 'n'), 'n');
if (strtolower($response) === 'n') {
$response = $project = false;
}
}
if ($project === false) {
$this->out(__d('cake_console', 'Aborting project creation.'));
return;
}
if ($this->bake($project)) {
$this->out(__d('cake_console', 'Project baked successfully!'));
return $path;
}
}
/**
* Uses composer to generate a new package using the cakephp/app project.
*
* @param string $path Project path
* @return mixed
*/
public function bake($path) {
$composer = $this->params['composer'];
if (!file_exists($composer)) {
$this->error(__d('cake_console', 'Cannot bake project. Could not find composer at "%s".', $composer));
return false;
}
$this->out(__d('cake_console', 'Downloading a new cakephp app from packagist.org'));
$command = 'php ' . escapeshellarg($composer) . ' create-project --dev cakephp/app ' . escapeshellarg($path);
$descriptorSpec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$process = proc_open(
$command,
$descriptorSpec,
$pipes
);
if (!is_resource($process)) {
$this->error(__d('cake_console', 'Could not start subprocess.'));
return false;
}
$output = $error = '';
fclose($pipes[0]);
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$error = stream_get_contents($pipes[2]);
fclose($pipes[2]);
proc_close($process);
if ($error) {
$this->error(__d('cake_console', 'Installation from packagist.org failed with: %s', $error));
return false;
}
$this->out($output);
return true;
}
/**
* Enables Configure::read('Routing.prefixes') in /app/Config/routes.php
*
* @param string $name Name to use as admin routing
* @return boolean Success
*/
public function cakeAdmin($name) {
$path = $this->appPath ?: APP;
$path .= 'Config/';
$File = new File($path . 'routes.php');
$contents = $File->read();
if (preg_match('%(\s*[/]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) {
$result = str_replace($match[0], "\n" . 'Configure::write(\'Routing.prefixes\', array(\'' . $name . '\'));', $contents);
if ($File->write($result)) {
Configure::write('Routing.prefixes', array($name));
return true;
}
}
return false;
}
/**
* Checks for Configure::read('Routing.prefixes') and forces user to input it if not enabled
*
* @return string Admin route to use
*/
public function getPrefix() {
$admin = '';
$prefixes = Configure::read('Routing.prefixes');
if (!empty($prefixes)) {
if (count($prefixes) === 1) {
return $prefixes[0] . '_';
}
if ($this->interactive) {
$this->out();
$this->out(__d('cake_console', 'You have more than one routing prefix configured'));
}
$options = array();
foreach ($prefixes as $i => $prefix) {
$options[] = $i + 1;
if ($this->interactive) {
$this->out($i + 1 . '. ' . $prefix);
}
}
$selection = $this->in(__d('cake_console', 'Please choose a prefix to bake with.'), $options, 1);
return $prefixes[$selection - 1] . '_';
}
if ($this->interactive) {
$this->hr();
$this->out(__d('cake_console', 'You need to enable %s in %s to use prefix routing.',
'Configure::write(\'Routing.prefixes\', array(\'admin\'))',
'/app/Config/routes.php'));
$this->out(__d('cake_console', 'What would you like the prefix route to be?'));
$this->out(__d('cake_console', 'Example: %s', 'www.example.com/admin/controller'));
while (!$admin) {
$admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin');
}
if ($this->cakeAdmin($admin) !== true) {
$this->out(__d('cake_console', 'Unable to write to %s.', '/app/Config/routes.php'));
$this->out(__d('cake_console', 'You need to enable %s in %s to use prefix routing.',
'Configure::write(\'Routing.prefixes\', array(\'admin\'))',
'/app/Config/routes.php'));
return $this->_stop();
}
return $admin . '_';
}
return '';
}
/**
* get the option parser.
*
* @return ConsoleOptionParser
*/
public function getOptionParser() {
$parser = parent::getOptionParser();
return $parser->description(
__d('cake_console', 'Generate a new CakePHP project skeleton.')
)->addArgument('name', array(
'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.')
))->addOption('empty', array(
'boolean' => true,
'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git')
))->addOption('theme', array(
'short' => 't',
'help' => __d('cake_console', 'Theme to use when baking code.')
))->addOption('composer', array(
'default' => ROOT . '/composer.phar',
'help' => __d('cake_console', 'The path to the composer executable.')
));
}
}