Tired of performing repetitive actions to start a new project on your local development environment? Help yourself a bit and automate some of this for your standard workflow by using your own script.
Starting a new or existing project usually consists of the following steps:
- repository clones
- create database and database user
- configure database credentials
- restore backup
- configure other environment variable / settings
- composer install
- npm install
- .htaccess
These steps can be automated so that they can be executed within a minute and you can get started with the project. The script is based on the package `symfony / console`, the creation of a class e.g.`setupCommand` and an executable php file with which the command can be started.
For more information about symfony / console see: https://symfony.com/doc/current/components/console.html
Code example local installation
To the execute method of the setupCommand we initialize a questionHelper that provides support in asking questions and suggestions to the user.
After the base is set to execute a command and to ask any questions, one can start with the questions and own steps to set up a project. Below is a code example on how to quickly set up a local installation for TYPO3. This example can be used for your base to create a "quick start" script.
<?php
namespace BeechIt\LocalEnvironmentSetup\Command;
/*
* This source file is proprietary property of Beech.it
* Date: 14-11-2016 13:36
* All code (c) Beech.it all rights reserved
*/
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
/**
* Class SetupCommand
*/
class SetupCommand extends Command
{
/**
* Configure the command with the name, description and help text
*/
protected function configure()
{
$this
->setName('setup:local')
->setDescription('Setup the local environment for the user')
->setHelp('This command lets you setup a local environment');
}
/**
* Execute command
*
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('<info>Welcome to the BeechIt project initializer</info>');
/** @var QuestionHelper $helper */
$helper = $this->getHelper('question');
$defaultRepoUrl = 'default repository url';
//Which repository should we use for the setup
$output->writeln('<info>Do you want to create a new project based on the default?</info>');
$newProjectQuestion = new ConfirmationQuestion('New project? [No]:', false);
$newProject = $helper->ask($input, $output, $newProjectQuestion);
if ($newProject) {
$output->writeln('<info>Create the new repository in gitlab and enter the url here.</info>');
$repositoryUrl = $helper->ask($input, $output, new Question(
'Repository url of new empty git repository:'
));
} else {
$output->writeln('<info>Please provide the existing repository url.</info>');
$repositoryUrl = $helper->ask($input, $output, new Question(
'Repository url of existing project [default]:',
$defaultRepoUrl
));
}
// under which directory the repository should exists (default to the repository name)
$dirSuggestion = preg_replace('/\.git$/i', '', basename($repositoryUrl)) ?: 'default';
$projectDirName = $helper->ask($input, $output, new Question(
'Enter the project dirname [' . $dirSuggestion . ']:',
$dirSuggestion
));
$this->shellExecute('git clone ' . $defaultRepoUrl . ' ' . $projectDirName, $output);
if ($newProject) {
$this->shellExecute('cd ' . $projectDirName . '; git remote set-url origin ' . $repositoryUrl, $output);
}
// Create the database
$dbName = '';
$output->writeln('<info>Please provide a name for the database with user and password to be created.</info>');
$output->writeln('<comment>The total length of the name is max 16 chars.</comment>');
while (true) {
$dbName = $helper->ask($input, $output, new Question(
'Project DB name/user: '
));
$dbName = trim($dbName);
if ($this->validDatabaseName($dbName)) {
break;
} else {
$output->writeln('<error>The entered name contains to many characters.</error>');
}
}
$rootUser = $helper->ask($input, $output, new Question('Enter the database root username [root]:', 'root'));
$passWordQuestion = new Question('Enter the database root password:');
$passWordQuestion->setHidden(true);
$passWordQuestion->setHiddenFallback(false);
$rootPassword = $helper->ask($input, $output, $passWordQuestion);
$shellOutput = $this->createDatabaseAndUser($output, $rootUser, $rootPassword, $dbName);
// When there is shell output, a error or message is provided by the database
// manually check/create the database before continuing
if ($shellOutput) {
$output->writeln('<error>There were warnings with creating the database, please fix these errors before continuing.</error>');
$output->writeln($shellOutput);
$continue = $helper->ask($input, $output,
new ConfirmationQuestion('I\'ve fixed the errors and created the database. I can continue with setup local development.'));
if (!$continue) {
return 10;
}
}
// Initialize correct typo3 environment settings based on your TYPO3 version
$typoVersion = $helper->ask($input, $output, new Question('TYPO3 Version 7/8 [8]:', '8'));
$this->createEnvironmentFile($projectDirName, $dbName, $typoVersion);
$projectPath = realpath('.') . '/' . $projectDirName . '/';
//Setup the local/development .htaccess
$this->shellExecute(
'ln -s ' . $projectPath . 'Web/.htaccess_development ' . $projectPath . '/Web/.htaccess',
$output
);
//Initialize dependencies and restore a backup
$this->shellExecute('composer install -d ' . $projectPath, $output);
$this->shellExecute($projectPath . 'typo3cms backup:restore dummy --plain-restore', $output);
$this->shellExecute('cd ' . $projectDirName . '; npm install', $output);
$output->writeln('<info>The project ' . $projectDirName . ' is created under path ' . $projectPath);
return 0;
}
/**
* Execute commands and output command info when in verbose mode
*
* @param $cmd
* @param OutputInterface $output
*/
private function shellExecute($cmd, $output)
{
if ($output->isVerbose()) {
$output->writeln('<info>Execute cmd: ' . $cmd . '</info>');
}
shell_exec($cmd);
}
/**
* Checks if the databaseName is valid
*
* @param $projectDatabase
* @return bool
*/
private function validDatabaseName($projectDatabase)
{
return !(strlen($projectDatabase) > 16);
}
/**
* Create the database and user with correct permissions and utf set
* For easier setup at your local enviroment databasename and username is the same
*
* @param OutputInterface $output
* @param $userName
* @param $password
* @param $newDatabaseName
* @return string
*/
protected function createDatabaseAndUser($output, $userName, $password, $newDatabaseName)
{
$createDatabaseUser = 'CREATE USER \'' . $newDatabaseName . '\'@\'localhost\' IDENTIFIED BY \'' . $newDatabaseName . '\';';
$grantUsages = 'GRANT USAGE ON * . * TO \'' . $newDatabaseName . '\'@\'localhost\' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;';
$createDatabase = 'CREATE DATABASE IF NOT EXISTS ' . $newDatabaseName . ' DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;';
$grantPrivileges = 'GRANT ALL PRIVILEGES ON ' . $newDatabaseName . ' . * TO \'' . $newDatabaseName . '\'@\'localhost\';';
$flushPrivileges = 'FLUSH PRIVILEGES;';
return $this->shellExecute(
'mysql -u' . $userName . ' -p' . $password .
' -e "' . $createDatabaseUser . $grantUsages . $createDatabase . $grantPrivileges . $flushPrivileges . '"',
$output
);
}
/**
* Creates the environmentFile for local development
*
* @param $projectPath
* @param $dbName
*/
private function createEnvironmentFile($projectPath, $dbName, $typoVersion)
{
$envFilePath = $projectPath . '/.env';
if (!file_exists($envFilePath)) {
if ((int)$typoVersion === 8) {
file_put_contents($envFilePath,
'TYPO3_CONTEXT="Development"' . PHP_EOL .
PHP_EOL .
PHP_EOL .
'# Credentials' . PHP_EOL .
'TYPO3__DB__Connections__Default__dbname="' . $dbName . '"' . PHP_EOL .
'TYPO3__DB__Connections__Default__password="' . $dbName . '"' . PHP_EOL .
'TYPO3__DB__Connections__Default__host="localhost"' . PHP_EOL .
'TYPO3__DB__Connections__Default__user="' . $dbName . '"' . PHP_EOL .
'TYPO3__DB__Connections__Default__port="3306"' . PHP_EOL .
'TYPO3__DB__Connections__Default__driver="mysqli"' . PHP_EOL .
'TYPO3__DB__Connections__Default__charset="utf8"' . PHP_EOL .
PHP_EOL .
'# Host specifics' . PHP_EOL .
PHP_EOL .
'## graphicsmagick path' . PHP_EOL .
'TYPO3__GFX__processor_path="/usr/local/bin/"' . PHP_EOL .
'TYPO3__GFX__processor_path_lzw="/usr/local/bin/"' . PHP_EOL .
PHP_EOL .
'# Secrets' . PHP_EOL .
'TYPO3__SYS__encryptionKey="PROVIDE_ENCRYPTION_KEY"' . PHP_EOL .
'TYPO3__BE__installToolPassword="INSTALL_TOOL_PASSWORD_HASH"' . PHP_EOL .
PHP_EOL
);
} else {
file_put_contents($envFilePath,
'TYPO3_CONTEXT="Development"' . PHP_EOL .
PHP_EOL .
PHP_EOL .
'# Credentials' . PHP_EOL .
'TYPO3__DB__database="' . $dbName . '"' . PHP_EOL .
'TYPO3__DB__host="localhost"' . PHP_EOL .
'TYPO3__DB__password="' . $dbName . '"' . PHP_EOL .
'TYPO3__DB__port="3306"' . PHP_EOL .
'TYPO3__DB__username="' . $dbName . '"' . PHP_EOL .
PHP_EOL .
'# Host specifics' . PHP_EOL .
PHP_EOL .
'## graphicsmagick path' . PHP_EOL .
'TYPO3__GFX__im_path="/usr/local/bin/"' . PHP_EOL .
'TYPO3__GFX__im_path_lzw="/usr/local/bin/"' . PHP_EOL .
PHP_EOL .
'# Secrets' . PHP_EOL .
'TYPO3__SYS__encryptionKey="PROVIDE_ENCRYPTION_KEY"' . PHP_EOL .
'TYPO3__BE__installToolPassword="INSTALL_TOOL_PASSWORD_HASH"' . PHP_EOL .
PHP_EOL
);
}
}
}
}php