diff --git a/.github/ISSUE_TEMPLATE/Bug.md b/.github/ISSUE_TEMPLATE/Bug.md index e473ad34..59f71b26 100644 --- a/.github/ISSUE_TEMPLATE/Bug.md +++ b/.github/ISSUE_TEMPLATE/Bug.md @@ -18,7 +18,7 @@ With that said, please fill in the information requested next. More information * Shlink Version: x.y.z * PHP Version: x.y.z * How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted swoole|Docker image -* Database engine used: MySQL|PostgreSQL|SQLite (x.y.z) +* Database engine used: MySQL|MariaDB|PostgreSQL|SQLite (x.y.z) #### Summary diff --git a/.github/ISSUE_TEMPLATE/Question_Support.md b/.github/ISSUE_TEMPLATE/Question_Support.md index 3e8eb206..885f866f 100644 --- a/.github/ISSUE_TEMPLATE/Question_Support.md +++ b/.github/ISSUE_TEMPLATE/Question_Support.md @@ -18,7 +18,7 @@ With that said, please fill in the information requested next. More information * Shlink Version: x.y.z * PHP Version: x.y.z * How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted swoole|Docker image -* Database engine used: MySQL|PostgreSQL|SQLite (x.y.z) +* Database engine used: MySQL|MariaDB|PostgreSQL|SQLite (x.y.z) #### Summary diff --git a/README.md b/README.md index 932d0b7d..41042163 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ A PHP-based self-hosted URL shortener that can be used to serve shortened URLs u First make sure the host where you are going to run shlink fulfills these requirements: * PHP 7.2 or greater with JSON, APCu, intl, curl, PDO and gd extensions enabled. -* MySQL, PostgreSQL or SQLite. +* MySQL, MariaDB, PostgreSQL or SQLite. * The web server of your choice with PHP integration (Apache or Nginx recommended). Then, you will need a built version of the project. There are a few ways to get it. @@ -49,7 +49,7 @@ Then, you will need a built version of the project. There are a few ways to get Despite how you built the project, you are going to need to install it now, by following these steps: -* If you are going to use MySQL or PostgreSQL, create an empty database with the name of your choice. +* If you are going to use MySQL, MariaDB or PostgreSQL, create an empty database with the name of your choice. * Recursively grant write permissions to the `data` directory. Shlink uses it to cache some information. * Setup the application by running the `bin/install` script. It is a command line tool that will guide you through the installation process. **Take into account that this tool has to be run directly on the server where you plan to host Shlink. Do not run it before uploading/moving it there.** * Expose shlink to the web, either by using a traditional web server + fast CGI approach, or by using a [swoole](https://www.swoole.co.uk/) non-blocking server. diff --git a/composer.json b/composer.json index 1515cfeb..3159566c 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "predis/predis": "^1.1", "shlinkio/shlink-common": "^2.0", "shlinkio/shlink-event-dispatcher": "^1.0", - "shlinkio/shlink-installer": "^2.0", + "shlinkio/shlink-installer": "^2.1", "shlinkio/shlink-ip-geolocation": "^1.0", "symfony/console": "^4.3", "symfony/filesystem": "^4.3", @@ -110,18 +110,25 @@ ], "test:ci": [ "@test:unit:ci", - "@test:db", + "@test:db:ci", "@test:api" ], "test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always --coverage-php build/coverage-unit.cov --testdox", "test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml --testdox", "test:db": [ + "@test:db:sqlite", + "@test:db:mysql", + "@test:db:maria", + "@test:db:postgres" + ], + "test:db:ci": [ "@test:db:sqlite", "@test:db:mysql", "@test:db:postgres" ], "test:db:sqlite": "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always -c phpunit-db.xml --coverage-php build/coverage-db.cov --testdox", "test:db:mysql": "DB_DRIVER=mysql composer test:db:sqlite", + "test:db:maria": "DB_DRIVER=maria composer test:db:sqlite", "test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite", "test:api": "bin/test/run-api-tests.sh", @@ -149,9 +156,11 @@ "test:ci": "Runs all test suites, generating all needed reports and logs for CI envs", "test:unit": "Runs unit test suites", "test:unit:ci": "Runs unit test suites, generating all needed reports and logs for CI envs", - "test:db": "Runs database test suites on a SQLite, MySQL and PostgreSQL", + "test:db": "Runs database test suites on a SQLite, MySQL, MariaDB and PostgreSQL", + "test:db:ci": "Runs database test suites on a SQLite, MySQL and PostgreSQL", "test:db:sqlite": "Runs database test suites on a SQLite database", "test:db:mysql": "Runs database test suites on a MySQL database", + "test:db:maria": "Runs database test suites on a MariaDB database", "test:db:postgres": "Runs database test suites on a PostgreSQL database", "test:api": "Runs API test suites", "test:pretty": "Runs all test suites and generates an HTML code coverage report", diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index 6da1fa88..4e8ebdaf 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -16,40 +16,41 @@ use function sys_get_temp_dir; $swooleTestingHost = '127.0.0.1'; $swooleTestingPort = 9999; -$buildDbConnection = function () { +$buildDbConnection = function (): array { $driver = env('DB_DRIVER', 'sqlite'); $isCi = env('TRAVIS', false); + $getMysqlHost = function (string $driver) { + return sprintf('shlink_db%s', $driver === 'mysql' ? '' : '_maria'); + }; - switch ($driver) { - case 'sqlite': - return [ - 'driver' => 'pdo_sqlite', - 'path' => sys_get_temp_dir() . '/shlink-tests.db', - ]; - case 'mysql': - return [ - 'driver' => 'pdo_mysql', - 'host' => $isCi ? '127.0.0.1' : 'shlink_db', - 'user' => 'root', - 'password' => $isCi ? '' : 'root', - 'dbname' => 'shlink_test', - 'charset' => 'utf8', - 'driverOptions' => [ - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', - ], - ]; - case 'postgres': - return [ - 'driver' => 'pdo_pgsql', - 'host' => $isCi ? '127.0.0.1' : 'shlink_db_postgres', - 'user' => 'postgres', - 'password' => $isCi ? '' : 'root', - 'dbname' => 'shlink_test', - 'charset' => 'utf8', - ]; - default: - return []; - } + $driverConfigMap = [ + 'sqlite' => [ + 'driver' => 'pdo_sqlite', + 'path' => sys_get_temp_dir() . '/shlink-tests.db', + ], + 'mysql' => [ + 'driver' => 'pdo_mysql', + 'host' => $isCi ? '127.0.0.1' : $getMysqlHost($driver), + 'user' => 'root', + 'password' => $isCi ? '' : 'root', + 'dbname' => 'shlink_test', + 'charset' => 'utf8', + 'driverOptions' => [ + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', + ], + ], + 'postgres' => [ + 'driver' => 'pdo_pgsql', + 'host' => $isCi ? '127.0.0.1' : 'shlink_db_postgres', + 'user' => 'postgres', + 'password' => $isCi ? '' : 'root', + 'dbname' => 'shlink_test', + 'charset' => 'utf8', + ], + ]; + $driverConfigMap['maria'] = $driverConfigMap['mysql']; + + return $driverConfigMap[$driver] ?? []; }; return [ diff --git a/data/infra/database_maria/.gitignore b/data/infra/database_maria/.gitignore new file mode 100755 index 00000000..d6b7ef32 --- /dev/null +++ b/data/infra/database_maria/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/docker-compose.override.yml.dist b/docker-compose.override.yml.dist index ec9d24da..ea0bee84 100644 --- a/docker-compose.override.yml.dist +++ b/docker-compose.override.yml.dist @@ -24,3 +24,9 @@ services: volumes: - /etc/passwd:/etc/passwd:ro - /etc/group:/etc/group:ro + + shlink_db_maria: + user: 1000:1000 + volumes: + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro diff --git a/docker-compose.yml b/docker-compose.yml index 0f9b12d7..34b9c64e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,7 @@ services: links: - shlink_db - shlink_db_postgres + - shlink_db_maria - shlink_redis shlink_swoole: @@ -38,6 +39,7 @@ services: links: - shlink_db - shlink_db_postgres + - shlink_db_maria - shlink_redis shlink_db: @@ -65,6 +67,18 @@ services: POSTGRES_DB: shlink PGDATA: /var/lib/postgresql/data/pgdata + shlink_db_maria: + container_name: shlink_db_maria + image: mariadb:10.2 + ports: + - "3308:3306" + volumes: + - ./:/home/shlink/www + - ./data/infra/database_maria:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: shlink + shlink_redis: container_name: shlink_redis image: redis:5.0-alpine diff --git a/docker/README.md b/docker/README.md index 9f62c818..aff3d997 100644 --- a/docker/README.md +++ b/docker/README.md @@ -56,16 +56,16 @@ docker exec -it shlink_container shlink The image comes with a working sqlite database, but in production you will probably want to usa a distributed database. -It is possible to use a set of env vars to make this shlink instance interact with an external MySQL or PostgreSQL database. +It is possible to use a set of env vars to make this shlink instance interact with an external MySQL, MariaDB or PostgreSQL database. -* `DB_DRIVER`: **[Mandatory]**. Use the value **mysql** or **postgres** to prevent the sqlite database to be used. +* `DB_DRIVER`: **[Mandatory]**. Use the value **mysql**, **maria** or **postgres** to prevent the sqlite database to be used. * `DB_NAME`: [Optional]. The database name to be used. Defaults to **shlink**. * `DB_USER`: **[Mandatory]**. The username credential for the database server. * `DB_PASSWORD`: **[Mandatory]**. The password credential for the database server. * `DB_HOST`: **[Mandatory]**. The host name of the server running the database engine. * `DB_PORT`: [Optional]. The port in which the database service is running. * Default value is based on the driver: - * **mysql** -> `3306` + * **mysql** or **maria** -> `3306` * **postgres** -> `5432` > PostgreSQL is supported since v1.16.1 of this image. Do not try to use it with previous versions. @@ -93,7 +93,7 @@ This is the complete list of supported env vars: * `SHORT_DOMAIN_HOST`: The custom short domain used for this shlink instance. For example **doma.in**. * `SHORT_DOMAIN_SCHEMA`: Either **http** or **https**. * `SHORTCODE_CHARS`: A charset to use when building short codes. Only needed when using more than one shlink instance ([Multi instance considerations](#multi-instance-considerations)). -* `DB_DRIVER`: **sqlite** (which is the default value), **mysql** or **postgres**. +* `DB_DRIVER`: **sqlite** (which is the default value), **mysql**, **maria** or **postgres**. * `DB_NAME`: The database name to be used when using an external database driver. Defaults to **shlink**. * `DB_USER`: The username credential to be used when using an external database driver. * `DB_PASSWORD`: The password credential to be used when using an external database driver. diff --git a/docker/config/shlink_in_docker.local.php b/docker/config/shlink_in_docker.local.php index ecfde4dc..d0744358 100644 --- a/docker/config/shlink_in_docker.local.php +++ b/docker/config/shlink_in_docker.local.php @@ -11,6 +11,7 @@ use function explode; use function file_exists; use function file_get_contents; use function file_put_contents; +use function Functional\contains; use function implode; use function Shlinkio\Shlink\Common\env; use function sprintf; @@ -22,10 +23,12 @@ $helper = new class { private const BASE62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; private const DB_DRIVERS_MAP = [ 'mysql' => 'pdo_mysql', + 'maria' => 'pdo_mysql', 'postgres' => 'pdo_pgsql', ]; private const DB_PORTS_MAP = [ 'mysql' => '3306', + 'maria' => '3306', 'postgres' => '5432', ]; @@ -85,7 +88,7 @@ $helper = new class { ]; } - $driverOptions = $driver !== 'mysql' ? [] : [ + $driverOptions = ! contains(['maria', 'mysql'], $driver) ? [] : [ // PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8', 1002 => 'SET NAMES utf8', ];