diff --git a/CHANGELOG.md b/CHANGELOG.md
index f0613e9..4cfe2a8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
All notable changes to this project will be documented in this file.
+## [1.1.0] - 2025-04-24
+### Added
+- New database option: MySQL.
+- New configuration option: `options.environment.database.rootPassword`.
+
+### Changed
+- Changed the default database for new environments to MySQL (from SQLite).
+
## [1.0.4] - 2025-04-24
### Fixed
- Fixed a critical autoloading issue after the package is globally installed.
diff --git a/README.md b/README.md
index 81b235c..61a8f8b 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
# Loom Spinner CLI
-
+
A streamlined environment management tool for PHP developers.
@@ -21,16 +21,13 @@ Effortlessly create custom Docker environments for each of your PHP projects. Ou
- **PHP 8.4** (includes XDebug & OpCache)
- **Nginx**
-- **SQLite3**
+- **MySQL 9.3**
- **NodeJS 23** (Node, NPM, & NPX)
Your project directory is automatically mounted to the PHP container, and the `public` directory is served via Nginx at
`http://localhost:`. Access the container directly from your terminal to execute unit tests or other
commands, all within an isolated environment.
-> **Note:** Loom Spinner CLI is in early development. For now, only SQLite is supported as the database, but more options
-> are on the way in future updates.
-
# Installation
**Requirements:**
diff --git a/composer.json b/composer.json
index 05de60c..eb6bd2e 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,7 @@
{
"name": "loomlabs/loom-spinner-cli",
"description": "A simple command-line Docker environment spinner for PHP.",
- "version": "1.0.4",
+ "version": "1.1.0",
"autoload": {
"psr-4": {
"Loom\\Spinner\\": "src/"
diff --git a/config/.template.env b/config/.template.env
index 77e79d6..b3ad961 100644
--- a/config/.template.env
+++ b/config/.template.env
@@ -7,4 +7,8 @@ PHP_VERSION=%s
PHP_PORT=%s
# Nginx
-NGINX_PORT=%s
\ No newline at end of file
+SERVER_PORT=%s
+
+# Database
+DATABASE_PORT=%s
+ROOT_PASSWORD=%s
\ No newline at end of file
diff --git a/config/mysql.yaml b/config/mysql.yaml
new file mode 100644
index 0000000..cad47a5
--- /dev/null
+++ b/config/mysql.yaml
@@ -0,0 +1,12 @@
+services:
+ mysql:
+ image: mysql:9.3.0
+ command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
+ ports:
+ - ${DATABASE_PORT}:3306
+ expose:
+ - "3306"
+ environment:
+ MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
+ volumes:
+ - ./data/${PROJECT_NAME}/mysql:/var/lib/mysql:cached
\ No newline at end of file
diff --git a/config/nginx.yaml b/config/nginx.yaml
index 6bb2d62..6e96ec9 100644
--- a/config/nginx.yaml
+++ b/config/nginx.yaml
@@ -3,7 +3,7 @@ services:
build:
context: ./nginx
ports:
- - ${NGINX_PORT}:80
+ - ${SERVER_PORT}:80
volumes:
- ${PROJECT_DIRECTORY}:/var/www/html:cached
- ./nginx/conf.d:/etc/nginx/conf.d
diff --git a/config/spinner.yaml b/config/spinner.yaml
index 1be09f7..ab34b00 100644
--- a/config/spinner.yaml
+++ b/config/spinner.yaml
@@ -9,4 +9,5 @@ options:
enabled: true
database:
enabled: true
- driver: sqlite3
\ No newline at end of file
+ driver: mysql
+ rootPassword: docker
\ No newline at end of file
diff --git a/src/Classes/File/DockerComposeFileBuilder.php b/src/Classes/File/DockerComposeFileBuilder.php
index 4a9300b..af1dc29 100644
--- a/src/Classes/File/DockerComposeFileBuilder.php
+++ b/src/Classes/File/DockerComposeFileBuilder.php
@@ -13,7 +13,7 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
/**
* @throws \Exception
*/
- public function __construct(Config $config)
+ public function __construct(Config $config, private array $ports)
{
return parent::__construct($config->getDataDirectory() . '/docker-compose.yaml', $config);
}
@@ -25,8 +25,16 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
{
$this->content = $this->config->getConfigFileContents('php.yaml');
- if ($this->config->isDatabaseEnabled($input) && in_array($this->config->getDatabaseDriver($input), ['sqlite3', 'sqlite'])) {
- $this->addSqliteDatabaseConfig();
+ if ($this->config->isDatabaseEnabled($input)) {
+ $databaseDriver = strtolower($this->config->getDatabaseDriver($input));
+
+ if (in_array($databaseDriver, ['sqlite3', 'sqlite'])) {
+ $this->addSqliteDatabaseConfig();
+ }
+
+ if ($databaseDriver === 'mysql') {
+ $this->addMysqlDatabaseConfig();
+ }
}
if ($this->config->isServerEnabled($input)) {
@@ -56,4 +64,12 @@ class DockerComposeFileBuilder extends AbstractFileBuilder
$sqlLiteConfig = str_replace('volumes:', '', $sqlLiteConfig);
$this->content .= $sqlLiteConfig;
}
+
+ private function addMysqlDatabaseConfig(): void
+ {
+ $mysqlConfig = str_replace('services:', '', $this->config->getConfigFileContents('mysql.yaml'));
+ $mysqlConfig = str_replace('${ROOT_PASSWORD}', $this->config->getEnvironmentOption('database', 'rootPassword'), $mysqlConfig);
+ $mysqlConfig = str_replace('${DATABASE_PORT}', (string) $this->ports['database'], $mysqlConfig);
+ $this->content.= $mysqlConfig;
+ }
}
\ No newline at end of file
diff --git a/src/Classes/File/PHPDockerFileBuilder.php b/src/Classes/File/PHPDockerFileBuilder.php
index 8fa5b00..d5f2cd5 100644
--- a/src/Classes/File/PHPDockerFileBuilder.php
+++ b/src/Classes/File/PHPDockerFileBuilder.php
@@ -31,9 +31,11 @@ class PHPDockerFileBuilder extends AbstractFileBuilder
$this->config->getConfigFileContents('php-fpm/opcache.ini')
);
- if ($this->config->isDatabaseEnabled($input) && in_array($this->config->getDatabaseDriver($input), ['sqlite3', 'sqlite'])) {
- $this->addNewLine();
- $this->content .= $this->config->getConfigFileContents('php-fpm/Sqlite.Dockerfile');
+ if ($this->config->isDatabaseEnabled($input)) {
+ if (in_array($this->config->getDatabaseDriver($input), ['sqlite3', 'sqlite'])) {
+ $this->addNewLine();
+ $this->content .= $this->config->getConfigFileContents('php-fpm/Sqlite.Dockerfile');
+ }
}
$this->content = str_replace('${NODE_VERSION}', (string) $this->config->getNodeVersion($input), $this->content);
diff --git a/src/Command/SpinCommand.php b/src/Command/SpinCommand.php
index b60a89c..35f6bb3 100644
--- a/src/Command/SpinCommand.php
+++ b/src/Command/SpinCommand.php
@@ -28,7 +28,8 @@ class SpinCommand extends AbstractSpinnerCommand
$this->portGenerator = new PortGenerator();
$this->ports = [
'php' => $this->portGenerator->generateRandomPort(),
- 'nginx' => $this->portGenerator->generateRandomPort(),
+ 'server' => $this->portGenerator->generateRandomPort(),
+ 'database' => $this->portGenerator->generateRandomPort(),
];
parent::__construct();
@@ -66,7 +67,7 @@ class SpinCommand extends AbstractSpinnerCommand
InputOption::VALUE_NONE,
'Set this flag to not include a database for your environment.'
)
- ->addOption('database', null, InputOption::VALUE_REQUIRED, 'The type of database to use (e.g., mysql, postgresql, sqlite).', null, ['sqlite'])
+ ->addOption('database', null, InputOption::VALUE_REQUIRED, 'The type of database to use (e.g., mysql, sqlite).', null, ['mysql', 'sqlite'])
->addOption('node', null, InputOption::VALUE_OPTIONAL, 'The Node.js version to use (e.g. 20).');
}
@@ -154,7 +155,9 @@ class SpinCommand extends AbstractSpinnerCommand
$input->getArgument('name'),
$this->config->getPhpVersion($input),
$this->ports['php'],
- $this->ports['nginx'],
+ $this->ports['server'],
+ $this->ports['database'],
+ $this->config->getEnvironmentOption('database', 'rootPassword')
)
);
}
@@ -166,7 +169,7 @@ class SpinCommand extends AbstractSpinnerCommand
{
$this->createProjectDataSubDirectory('php-fpm');
- (new DockerComposeFileBuilder($this->config))->build($input)->save();
+ (new DockerComposeFileBuilder($this->config, $this->ports))->build($input)->save();
}
/**