<?php

/**
 * Joomla! Content Management System
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\CMS\Service\Provider;

use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\Mysql\MysqlDriver;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;

// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
 * Service provider for the application's database dependency
 *
 * @since  4.0.0
 */
class Database implements ServiceProviderInterface
{
    /**
     * Registers the service provider with a DI container.
     *
     * @param   Container  $container  The DI container.
     *
     * @return  void
     *
     * @since   4.0.0
     */
    public function register(Container $container)
    {
        $container->alias('db', DatabaseInterface::class)
            ->alias('DatabaseDriver', DatabaseInterface::class)
            ->alias(DatabaseDriver::class, DatabaseInterface::class)
            ->share(
                DatabaseInterface::class,
                function (Container $container) {
                    $conf = $container->get('config');

                    /**
                     * @todo: This 'sensible' default is required in the installer for now. Eventually we need to
                     *        refactor the installer so it is not required
                     */
                    $dbtype = $conf->get('dbtype', 'mysqli');

                    /*
                     * In Joomla! 3.x and earlier the `mysql` type was used for the `ext/mysql` PHP extension, which is no longer supported.
                     * The `pdomysql` type represented the PDO MySQL adapter.  With the Framework's package in use, the PDO MySQL adapter
                     * is now the `mysql` type.  Therefore, we check two conditions:
                     *
                     * 1) Is the type `pdomysql`, if so switch to `mysql`
                     * 2) Is the type `mysql`, if so make sure PDO MySQL is supported and if not switch to `mysqli`
                     *
                     * For these cases, if a connection cannot be made with MySQLi, the database API will handle throwing an Exception
                     * so we don't need to make any additional checks for MySQLi.
                     */
                    if (strtolower($dbtype) === 'pdomysql') {
                        $dbtype = 'mysql';
                    }

                    if (strtolower($dbtype) === 'mysql') {
                        if (!MysqlDriver::isSupported()) {
                            $dbtype = 'mysqli';
                        }
                    }

                    /*
                     * Joomla! 4.0 removes support for the `ext/pgsql` PHP extension.  To help with the migration, we will migrate the configuration
                     * to the PDO PostgreSQL driver regardless of if the environment supports it.  Instead of getting a "driver not found" type of
                     * error, this will instead force the API to report that the driver is not supported.
                     */
                    if (strtolower($dbtype) === 'postgresql') {
                        $dbtype = 'pgsql';
                    }

                    $options = [
                        'driver'   => $dbtype,
                        'host'     => $conf->get('host'),
                        'user'     => $conf->get('user'),
                        'password' => $conf->get('password'),
                        'database' => $conf->get('db'),
                        'prefix'   => $conf->get('dbprefix'),
                    ];

                    if ((int) $conf->get('dbencryption') !== 0) {
                        $options['ssl'] = [
                            'enable'             => true,
                            'verify_server_cert' => (bool) $conf->get('dbsslverifyservercert'),
                        ];

                        foreach (['cipher', 'ca', 'key', 'cert'] as $value) {
                            $confVal = trim($conf->get('dbssl' . $value, ''));

                            if ($confVal !== '') {
                                $options['ssl'][$value] = $confVal;
                            }
                        }
                    }

                    // Enable utf8mb4 connections for mysql adapters
                    if (strtolower($dbtype) === 'mysqli') {
                        $options['utf8mb4'] = true;
                    }

                    if (strtolower($dbtype) === 'mysql') {
                        $options['charset'] = 'utf8mb4';
                    }

                    if (JDEBUG) {
                        $options['monitor'] = new \Joomla\Database\Monitor\DebugMonitor();
                    }

                    try {
                        $db = DatabaseDriver::getInstance($options);
                    } catch (\RuntimeException $e) {
                        if (!headers_sent()) {
                            header('HTTP/1.1 500 Internal Server Error');
                        }

                        jexit('Database Error: ' . $e->getMessage());
                    }

                    $db->setDispatcher($container->get(DispatcherInterface::class));

                    return $db;
                },
                true
            );
    }
}
