Compare commits

..

2 commits

Author SHA1 Message Date
Daniel Winning
acf87efdb9 Nginx setup 2025-04-13 20:07:48 +01:00
Daniel Winning
f276d19bc8 Fix setting PHP version in .env 2025-04-13 13:35:39 +01:00
13 changed files with 173 additions and 26 deletions

3
.gitignore vendored
View file

@ -1,3 +1,4 @@
/.idea /.idea
/vendor /vendor
composer.lock composer.lock
/public/*

View file

@ -1,6 +1,10 @@
# Project Settings
PROJECT_DIRECTORY=%s PROJECT_DIRECTORY=%s
PROJECT_NAME=%s PROJECT_NAME=%s
PHP_VERSION=%s
# Ports # PHP
PHP_PORT=%s PHP_VERSION=%s
PHP_PORT=%s
# Nginx
NGINX_PORT=%s

9
config/nginx.yaml Normal file
View file

@ -0,0 +1,9 @@
services:
nginx:
build:
context: ./nginx
ports:
- ${NGINX_PORT}:80
volumes:
- ${PROJECT_DIRECTORY}:/var/www/html:cached
- ./nginx/conf.d:/etc/nginx/conf.d

5
config/nginx/Dockerfile Normal file
View file

@ -0,0 +1,5 @@
FROM nginx:1.23-alpine
CMD ["nginx", "-g", "daemon off;"]
EXPOSE 80 443

View file

@ -0,0 +1,25 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
index index.php index.html;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+`.php)(/.+)$;
fastcgi_pass php:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}

View file

@ -4,4 +4,6 @@ options:
version: 8.4 version: 8.4
node: node:
enabled: true enabled: true
version: 20 version: 23
server:
enabled: true

View file

@ -52,13 +52,25 @@ class Config
*/ */
public function isNodeEnabled(InputInterface $input): bool public function isNodeEnabled(InputInterface $input): bool
{ {
if ($input->getOption('node-disabled')) { if ($input->getOption('disable-node')) {
return false; return false;
} }
return $this->getEnvironmentOption('node', 'enabled'); return $this->getEnvironmentOption('node', 'enabled');
} }
/**
* @throws \Exception
*/
public function isServerEnabled(InputInterface $input): bool
{
if ($input->getOption('disable-server')) {
return false;
}
return $this->getEnvironmentOption('server', 'enabled');
}
/** /**
* @throws \Exception * @throws \Exception
*/ */
@ -109,8 +121,10 @@ class Config
'envTemplate' => new SpinnerFilePath('config/.template.env'), 'envTemplate' => new SpinnerFilePath('config/.template.env'),
'data' => new SpinnerFilePath('data'), 'data' => new SpinnerFilePath('data'),
'phpYamlTemplate' => new SpinnerFilePath('config/php.yaml'), 'phpYamlTemplate' => new SpinnerFilePath('config/php.yaml'),
'nginxYamlTemplate' => new SpinnerFilePath('config/nginx.yaml'),
'phpFpmDataDirectory' => new SpinnerFilePath('config/php-fpm'), 'phpFpmDataDirectory' => new SpinnerFilePath('config/php-fpm'),
DataPathInterface::CONFIG_PHP_FPM_DIRECTORY => new SpinnerFilePath(DataPathInterface::CONFIG_PHP_FPM_DIRECTORY), DataPathInterface::CONFIG_PHP_FPM_DOCKERFILE => new SpinnerFilePath(DataPathInterface::CONFIG_PHP_FPM_DOCKERFILE),
DataPathInterface::CONFIG_NGINX_DOCKERFILE => new SpinnerFilePath(DataPathInterface::CONFIG_NGINX_DOCKERFILE),
'nodeDockerfileTemplate' => new SpinnerFilePath('config/php-fpm/Node.Dockerfile'), 'nodeDockerfileTemplate' => new SpinnerFilePath('config/php-fpm/Node.Dockerfile'),
]); ]);
} }

View file

@ -14,7 +14,7 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
*/ */
public function __construct(Config $config) public function __construct(Config $config)
{ {
$projectDockerCompose = $this->config->getFilePaths()->get('projectDockerCompose'); $projectDockerCompose = $config->getFilePaths()->get('projectDockerCompose');
if (!$projectDockerCompose instanceof SpinnerFilePath) { if (!$projectDockerCompose instanceof SpinnerFilePath) {
throw new \Exception('Project Docker Compose file path not found.'); throw new \Exception('Project Docker Compose file path not found.');
@ -23,12 +23,35 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
return parent::__construct($projectDockerCompose, $config); return parent::__construct($projectDockerCompose, $config);
} }
/**
* @throws \Exception
*/
public function build(InputInterface $input): DockerComposeFileBuilder public function build(InputInterface $input): DockerComposeFileBuilder
{ {
$this->content = file_get_contents( $this->content = file_get_contents(
$this->config->getFilePaths()->get('phpYamlTemplate')->getAbsolutePath() $this->config->getFilePaths()->get('phpYamlTemplate')->getAbsolutePath()
); );
if ($this->config->isServerEnabled($input)) {
$this->addNginxConfig();
}
return $this; return $this;
} }
private function addNginxConfig(): void
{
$this->content .= str_replace(
'services:',
'',
file_get_contents(
$this->config->getFilePaths()->get('nginxYamlTemplate')->getAbsolutePath()
)
);
$this->content = str_replace(
'./nginx/conf.d',
(new SpinnerFilePath('config/nginx/conf.d'))->getAbsolutePath(),
$this->content
);
}
} }

View file

@ -6,5 +6,6 @@ namespace Loom\Spinner\Classes\File\Interface;
interface DataPathInterface interface DataPathInterface
{ {
public const string CONFIG_PHP_FPM_DIRECTORY = 'config/php-fpm/Dockerfile'; public const string CONFIG_PHP_FPM_DOCKERFILE = 'config/php-fpm/Dockerfile';
public const string CONFIG_NGINX_DOCKERFILE = 'config/nginx/Dockerfile';
} }

View file

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Loom\Spinner\Classes\File;
use Loom\Spinner\Classes\Config\Config;
use Loom\Spinner\Classes\File\Interface\DataPathInterface;
use Symfony\Component\Console\Input\InputInterface;
class NginxDockerFileBuilder extends AbstractFileBuilder
{
/**
* @throws \Exception
*/
public function __construct(Config $config)
{
$projectNginxDockerfilePath = $config->getFilePath('projectNginxDockerfile');
if (!$projectNginxDockerfilePath instanceof SpinnerFilePath) {
throw new \Exception('Project PHP-FPM Dockerfile not found');
}
return parent::__construct($projectNginxDockerfilePath, $config);
}
public function build(InputInterface $input): AbstractFileBuilder
{
$this->content = file_get_contents(
$this->config->getFilePaths()
->get(DataPathInterface::CONFIG_NGINX_DOCKERFILE)
->getAbsolutePath()
);
return $this;
}
}

View file

@ -44,7 +44,7 @@ class PHPDockerFileBuilder extends AbstractFileBuilder
private function setInitialContent(): void private function setInitialContent(): void
{ {
$this->content = file_get_contents( $this->content = file_get_contents(
$this->config->getFilePaths()->get(DataPathInterface::CONFIG_PHP_FPM_DIRECTORY)->getAbsolutePath() $this->config->getFilePaths()->get(DataPathInterface::CONFIG_PHP_FPM_DOCKERFILE)->getAbsolutePath()
); );
} }
} }

View file

@ -94,17 +94,13 @@ class AbstractSpinnerCommand extends Command implements ConsoleCommandInterface
new SpinnerFilePath(sprintf('data/environments/%s/docker-compose.yml', $input->getArgument('name'))), new SpinnerFilePath(sprintf('data/environments/%s/docker-compose.yml', $input->getArgument('name'))),
'projectDockerCompose' 'projectDockerCompose'
); );
$this->config->addFilePath(
new SpinnerFilePath(sprintf('data/environments/%s/php-fpm', $input->getArgument('name'))),
'projectPhpFpmDirectory'
);
$this->config->addFilePath( $this->config->addFilePath(
new SpinnerFilePath(sprintf('data/environments/%s/php-fpm/Dockerfile', $input->getArgument('name'))), new SpinnerFilePath(sprintf('data/environments/%s/php-fpm/Dockerfile', $input->getArgument('name'))),
'projectPhpFpmDockerfile' 'projectPhpFpmDockerfile'
); );
$this->config->addFilePath( $this->config->addFilePath(
new SpinnerFilePath(sprintf('data/environments/%s/php-fpm/Node.Dockerfile', $input->getArgument('name'))), new SpinnerFilePath(sprintf('data/environments/%s/nginx/Dockerfile', $input->getArgument('name'))),
'projectPhpFpmNodeDockerfile' 'projectNginxDockerfile'
); );
$this->config->addFilePath( $this->config->addFilePath(
new FilePath($this->config->getFilePaths()->get('project')->getAbsolutePath() . DIRECTORY_SEPARATOR . 'spinner.yaml'), new FilePath($this->config->getFilePaths()->get('project')->getAbsolutePath() . DIRECTORY_SEPARATOR . 'spinner.yaml'),

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Loom\Spinner\Command; namespace Loom\Spinner\Command;
use Loom\Spinner\Classes\File\DockerComposeFileBuilder; use Loom\Spinner\Classes\File\DockerComposeFileBuilder;
use Loom\Spinner\Classes\File\NginxDockerFileBuilder;
use Loom\Spinner\Classes\File\PHPDockerFileBuilder; use Loom\Spinner\Classes\File\PHPDockerFileBuilder;
use Loom\Spinner\Classes\File\SpinnerFilePath; use Loom\Spinner\Classes\File\SpinnerFilePath;
use Loom\Spinner\Classes\OS\PortGenerator; use Loom\Spinner\Classes\OS\PortGenerator;
@ -26,6 +27,7 @@ class SpinCommand extends AbstractSpinnerCommand
$this->portGenerator = new PortGenerator(); $this->portGenerator = new PortGenerator();
$this->ports = [ $this->ports = [
'php' => $this->portGenerator->generateRandomPort(), 'php' => $this->portGenerator->generateRandomPort(),
'nginx' => $this->portGenerator->generateRandomPort(),
]; ];
parent::__construct(); parent::__construct();
@ -46,7 +48,13 @@ class SpinCommand extends AbstractSpinnerCommand
'The PHP version to use (e.g., 8.0).' 'The PHP version to use (e.g., 8.0).'
) )
->addOption( ->addOption(
'node-disabled', 'disable-node',
null,
InputOption::VALUE_NONE,
'Set this flag to disable Node.js for your environment.'
)
->addOption(
'disable-server',
null, null,
InputOption::VALUE_NONE, InputOption::VALUE_NONE,
'Set this flag to disable Node.js for your environment.' 'Set this flag to disable Node.js for your environment.'
@ -71,9 +79,9 @@ class SpinCommand extends AbstractSpinnerCommand
$this->style->text('Creating project data...'); $this->style->text('Creating project data...');
$this->createProjectData($input); $this->createProjectData($input);
// $command = $this->buildDockerComposeCommand(sprintf('-p %s up', $input->getArgument('name'))); $command = $this->buildDockerComposeCommand(sprintf('-p %s up', $input->getArgument('name')));
//
// passthru($command); passthru($command);
return Command::SUCCESS; return Command::SUCCESS;
} }
@ -97,7 +105,7 @@ class SpinCommand extends AbstractSpinnerCommand
$this->createProjectDataDirectory(); $this->createProjectDataDirectory();
$this->createEnvironmentFile($input); $this->createEnvironmentFile($input);
$this->buildDockerComposeFile($input); $this->buildDockerComposeFile($input);
$this->buildDockerfile($input); $this->buildDockerfiles($input);
} }
/** /**
@ -131,8 +139,9 @@ class SpinCommand extends AbstractSpinnerCommand
file_get_contents($this->config->getFilePaths()->get('envTemplate')->getAbsolutePath()), file_get_contents($this->config->getFilePaths()->get('envTemplate')->getAbsolutePath()),
$this->config->getFilePaths()->get('project')->getAbsolutePath(), $this->config->getFilePaths()->get('project')->getAbsolutePath(),
$input->getArgument('name'), $input->getArgument('name'),
$input->getOption('php'), $this->config->getPhpVersion($input),
$this->getPort('php'), $this->getPort('php'),
$this->getPort('nginx'),
) )
); );
} }
@ -144,9 +153,22 @@ class SpinCommand extends AbstractSpinnerCommand
{ {
$this->createProjectPhpFpmDirectory(); $this->createProjectPhpFpmDirectory();
if ($this->config->isServerEnabled($input)) {
$this->createProjectNginxDirectory();
(new NginxDockerFileBuilder($this->config))->build($input)->save();
}
(new DockerComposeFileBuilder($this->config))->build($input)->save(); (new DockerComposeFileBuilder($this->config))->build($input)->save();
} }
/**
* @throws \Exception
*/
private function buildDockerfiles(InputInterface $input): void
{
(new PHPDockerFileBuilder($this->config))->build($input)->save();
}
/** /**
* @throws \Exception * @throws \Exception
*/ */
@ -166,13 +188,21 @@ class SpinCommand extends AbstractSpinnerCommand
/** /**
* @throws \Exception * @throws \Exception
*/ */
private function buildDockerfile(InputInterface $input): void private function createProjectNginxDirectory(): void
{ {
(new PHPDockerFileBuilder($this->config))->build($input)->save(); $projectData = $this->config->getFilePaths()->get('projectData');
if (!$projectData instanceof SpinnerFilePath) {
throw new \Exception('Invalid project data directory provided.');
}
if (!file_exists($projectData->getProvidedPath() . '/nginx')) {
mkdir($projectData->getProvidedPath() . '/nginx', 0777, true);
}
} }
private function getPort(string $service): int private function getPort(string $service): ?int
{ {
return $this->ports[$service] ?? $this->portGenerator->generateRandomPort(); return $this->ports[$service];
} }
} }