Zo zet je binnen een minuut een project op

Moe van telkens weer herhalende handelingen uitvoeren om een nieuw project op te starten op je lokale development omgeving? Help jezelf een handje om dit voor een gedeelte te automatiseren voor je standaard werkwijze door middel van je eigen script.

Het opstarten van een nieuw of bestaand project bestaat meestal uit de volgende stappen:

  • Repository clonen
  • Database en database gebruiker aanmaken
  • Database credentials configureren
  • Backup terugzetten
  • Andere omgevings variable/settings configureren
  • Composer install
  • Npm install
  • .htaccess instellen

Deze stappen kunnen geautomatiseerd worden zodat deze binnen een minuut uitgevoerd kunnen worden en je aan de slag kunt met het project. Als basis voor het script wordt er gebruikt gemaakt van het package `symfony/console`, het aanmaken van een class bv `setupCommand` en executable php file waarmee het commando gestart kan worden.

Voor meer informatie over symfony/console zie https://symfony.com/doc/current/components/console.html

Code voorbeeld lokale installatie

Aan de execute methode van de setupCommand initializeren we een questionHelper die ondersteuning biedt in het stellen van vragen en suggesties aan de gebruiker.

Nadat de basis staat om een commando uit te voeren en om eventuele vragen te stellen kan er begonnen worden aan de vragen en eigen stappen om een project op te zetten. Hieronder een code voorbeeld hoe er snel een lokale installatie wordt opgezet voor TYPO3. Dit voorbeeld kan gebruikt worden voor jouw basis om een “snel aan de slag” script te maken.

<?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
                );
            }
        }
    }
}
< Terug naar overzicht

Ruud Silvrants

Developer

TYPO3 tovenaar. Duikt ook in webapplicaties. Laat zich nooit opjagen. Heeft eindelijk teckel Meggie zindelijk gekregen. 

#TYPO3 #HTML/CSS #PHP