digipolisgent/robo-digipolis-deploy

View on GitHub
src/BackupManager/Databases/MysqlDatabase.php

Summary

Maintainability
A
2 hrs
Test Coverage
B
80%
<?php

namespace DigipolisGent\Robo\Task\Deploy\BackupManager\Databases;

use District09\BackupManager\Databases\MysqlDatabase as Mysql;

class MysqlDatabase extends Mysql
{
    protected $tableList = [];
    /**
     * Config for this database.
     *
     * @var array
     */
    protected $config;

    /**
     * {@inheritdoc}
     */
    public function handles($type)
    {
        return strtolower($type) == 'mysql';
    }

    /**
     * {@inheritdoc}
     */
    public function setConfig(array $config)
    {
        $this->config = $config;
    }

    /**
     * {@inheritdoc}
     */
    public function getDumpCommandLine($outputPath)
    {
        $this->config += [
            'ignoreTables' => [],
            'structureTables' => [],
            'tables' => [],
            'dataOnly' => false,
            'orderedDump' => false,
            'singleTransaction' => true,
            'extra' => '',
        ];
        $this->expandTableNames();
        $command = '(mysqldump {{credentials}} {{tables}} {{options}} {{ignore}}';
        $credentials = $this->getCredentials();
        $tables = $this->getTables();
        $options = $this->getOptions();
        $ignore = $this->getIgnore();
        $structureTables = $this->getStructureTables();
        $file = escapeshellarg($outputPath);
        if ($structureTables) {
            $command .= ' && mysqldump {{credentials}} {{structureTables}} --no-data {{options}}';
        }
        $command .= ') > {{file}}';
        return strtr(
            $command,
            [
                '{{credentials}}' => $credentials,
                '{{tables}}' => $tables,
                '{{options}}' => $options,
                '{{ignore}}' => $ignore,
                '{{structureTables}}' => $structureTables,
                '{{file}}' => $file,
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getRestoreCommandLine($inputPath)
    {
        return sprintf(
            'mysql --host=%s --port=%s --user=%s --password=%s %s -e "source %s"',
            escapeshellarg($this->config['host']),
            escapeshellarg($this->config['port']),
            escapeshellarg($this->config['user']),
            escapeshellarg($this->config['pass']),
            escapeshellarg($this->config['database']),
            $inputPath
        );
    }

    /**
     * Get the credential options for the command.
     *
     * @return string
     */
    protected function getCredentials()
    {
        // Database credentials.
        $credentialArgs = [
            '--host=%s --port=%s --user=%s --password=%s %s',
            escapeshellarg($this->config['host']),
            escapeshellarg($this->config['port']),
            escapeshellarg($this->config['user']),
            escapeshellarg($this->config['pass']),
            escapeshellarg($this->config['database']),
        ];
        return call_user_func_array('sprintf', $credentialArgs);
    }

    /**
     * Get the table arguments for the command.
     *
     * @return string
     */
    protected function getTables()
    {
        if (empty($this->config['tables'])) {
            return '';
        }
        $tables = [];
        // Tables specified in both tables and structureTables should only
        // export their structure. @see getStructureTables().
        $allTables = array_diff($this->config['tables'], $this->config['structureTables']);
        foreach ($allTables as $table) {
            $tables[] = escapeshellarg($table);
        }
        return implode($tables);
    }

    /**
     * Get the command options for the command.
     *
     * @return string
     */
    protected function getOptions()
    {
        $options = [
            '--routines',
        ];

        if ($this->config['dataOnly']) {
            $options[] = '--no-create-info';
        }
        if ($this->config['orderedDump']) {
            $options[] = '--skip-extended-insert';
            $options[] = '--order-by-primary';
        }
        if ($this->config['singleTransaction']) {
            $options[] = '--single-transaction';
        }
        if ($this->config['extra']) {
            $options[] = $this->config['extra'];
        }
        return implode(' ', $options);
    }

    /**
     * Get the ignore table options for the command.
     *
     * @return string
     */
    protected function getIgnore()
    {
        if (!empty($this->config['tables'])) {
            return '';
        }
        $ignoreTables = array_merge($this->config['structureTables'], $this->config['ignoreTables']);
        // Append the ignore-table options.
        $ignoreArgs = [];
        foreach ($ignoreTables as $table) {
            $ignoreArgs[] = escapeshellarg($this->config['database'] . '.' . $table);
        }
        array_unshift($ignoreArgs, str_repeat(' --ignore-table=%s', count($ignoreArgs)));
        return trim(call_user_func_array('sprintf', $ignoreArgs));
    }

    /**
     * Get the structure tables for the command.
     *
     * @return string
     */
    protected function getStructureTables()
    {
        if (empty($this->config['structureTables'])) {
            return '';
        }
        $structureTables = [];
        foreach ($this->config['structureTables'] as $table) {
            $structureTables[] = escapeshellarg($table);
        }
        return implode(' ', $structureTables);
    }

    protected function expandTableNames()
    {
        if (empty($this->tableList)) {
            $dsn = 'mysql:host=' . $this->config['host']
                . ';port=' . $this->config['port']
                . ';dbname=' . $this->config['database'];
            $db = new \PDO($dsn, $this->config['user'], $this->config['pass']);
            $sql = $db->query('SHOW TABLES');
            $this->tableList = $sql->fetchAll(\PDO::FETCH_COLUMN);
        }
        foreach (['ignoreTables', 'structureTables', 'tables'] as $tableOption) {
            // Table name expansion based on `*` wildcard.
            $expandedTables = array();
            foreach ($this->config[$tableOption] as $table) {
                // Only deal with table names containing a wildcard.
                if (strpos($table, '*') === false) {
                    $expandedTables[] = $table;
                    continue;
                }
                $pattern = '/^' . str_replace('*', '.*', $table) . '$/i';
                // Merge those existing tables which match the pattern with the rest of
                // the expanded table names.
                $expandedTables += preg_grep($pattern, $this->tableList);
            }
            $this->config[$tableOption] = array_unique(array_intersect($expandedTables, $this->tableList));
            sort($this->config[$tableOption]);
        }
    }

    public function setTableList($tableList)
    {
        $this->tableList = $tableList;
    }
}