I am trying to run my unit test and create a database during setup. For some reason I am getting the error Unknown database 'coretest'. If I create the database though manually and run the test then I get Can't create database 'coretest'; database exists.
The drop database statement works just now the create database.
Here is my setUP and tearDown methods:
class TestCase extends Illuminate\Foundation\Testing\TestCase {
/**
* Default preparation for each test
*/
public function setUp() {
parent::setUp();
DB::statement('create database coretest;');
Artisan::call('migrate');
$this->seed();
Mail::pretend(true);
}
public function tearDown() {
parent::tearDown();
DB::statement('drop database coretest;');
}
}
The reason why you get this error is simply because laravel tries to connect to database specified in config, which doesn't exist.
The solution is to build your own PDO connection from the settings without specifying database (PDO allows this) and run CREATE DATABASE $dbname statement using it.
We used this approach for testing in our project without any problem.
Here some code:
<?php
/**
* Bootstrap file for (re)creating database before running tests
*
* You only need to put this file in "bootstrap" directory of the project
* and change "bootstrap" phpunit parameter within "phpunit.xml"
* from "bootstrap/autoload.php" to "bootstap/testing.php"
*/
$testEnvironment = 'testing';
$config = require("app/config/{$testEnvironment}/database.php");
extract($config['connections'][$config['default']]);
$connection = new PDO("{$driver}:user={$username} password={$password}");
$connection->query("DROP DATABASE IF EXISTS ".$database);
$connection->query("CREATE DATABASE ".$database);
require_once('app/libraries/helpers.php');
// run migrations for packages
foreach(glob('vendor/*/*', GLOB_ONLYDIR) as $package) {
$packageName = substr($package, 7); // drop "vendor" prefix
passthru("./artisan migrate --package={$packageName} --env={$testEnvironment}");
}
passthru('./artisan migrate --env='.$testEnvironment);
require('autoload.php'); // run laravel's original bootstap file
neoascetic has the best answer because essentially you have to boot laravel's database config file again.
So, a clever hack is to create database again after you have dropped it. No need to touch config/database.
public function setUp() {
parent::setUp();
Artisan::call('migrate');
$this->seed();
Mail::pretend(true);
}
public function tearDown() {
parent::tearDown();
DB::statement('drop database coretest;');
DB::statement('create database coretest;');
}
create it like this:
public function setUp() {
parent::setUp();
$pdo = new PDO(
"mysql:host=localhost",
config('database.connections.mysql.username'),
config('database.connections.mysql.password')
);
$pdo->query('CREATE DATABASE test_database');
// set up the new database as the default
config()->set('database.connections.mysql.database', 'test_database');
}
I feel like I have a much cleaner way of doing this. Just execute the commands normally through the shell.
$host = Config::get('database.connections.mysql.host');
$database = Config::get('database.connections.mysql.database');
$username = Config::get('database.connections.mysql.username');
$password = Config::get('database.connections.mysql.password');
echo shell_exec('mysql -h ' . $host . ' -u ' . $username . ' -p' . $password . ' -e "DROP DATABASE ' . $database . '"');
echo shell_exec('mysql -h ' . $host . ' -u ' . $username . ' -p' . $password . ' -e "CREATE DATABASE ' . $database . '"');
In Laravel 5 it's possible to call migrations internally to the Laravel process which ends up running a good bit quicker than using external commands.
In TestCase::setUp (or earlier), call the migration command with:
$kernel = app('Illuminate\Contracts\Console\Kernel');
$kernel->call('migrate');
Related
I'm working on a project that does NOT have a copy of production DB on development environment.
Sometimes we have an issue with DB migrations - they pass on dev DB but fail in production/testing.
It's often beacuse Dev environent data is loaded from Fixtures that use the latest entities - filling all tables properly.
Is there any easy way to make sure Doctrine Migration(s) will pass in production?
Do you have/know any way to write an automatic tests that will make sure data will be migrated properly without downloading the production/testing DB and running the migration manually?
I would like to avoid downloading a production/testing DB to dev machine so I can check migrations becasue that DB contains private data and it can be quite big.
First, you need to create a sample database dump in state before the migration. For MySQL use mysqldump. For postgres pg_dump, e.g.:
mysqldump -u root -p mydatabase > dump-2018-02-20.sql
pg_dump -Upostgres --inserts --encoding utf8 -f dump-2018-02-20.sql mydatabase
Then create an abstract class for all migrations tests (I assume you have configured a separate database for integration testing in config_test.yml):
abstract class DatabaseMigrationTestCase extends WebTestCase {
/** #var ResettableContainerInterface */
protected $container;
/** #var Application */
private $application;
protected function setUp() {
$this->container = self::createClient()->getContainer();
$kernel = $this->container->get('kernel');
$this->application = new Application($kernel);
$this->application->setAutoExit(false);
$this->application->setCatchExceptions(false);
$em = $this->container->get(EntityManagerInterface::class);
$this->executeCommand('doctrine:schema:drop --force');
$em->getConnection()->exec('DROP TABLE IF EXISTS public.migration_versions');
}
protected function loadDump(string $name) {
$em = $this->container->get(EntityManagerInterface::class);
$em->getConnection()->exec(file_get_contents(__DIR__ . '/dumps/dump-' . $name . '.sql'));
}
protected function executeCommand(string $command): string {
$input = new StringInput("$command --env=test");
$output = new BufferedOutput();
$input->setInteractive(false);
$returnCode = $this->application->run($input, $output);
if ($returnCode != 0) {
throw new \RuntimeException('Failed to execute command. ' . $output->fetch());
}
return $output->fetch();
}
protected function migrate(string $toVersion = '') {
$this->executeCommand('doctrine:migrations:migrate ' . $toVersion);
}
}
Example migration test:
class Version20180222232445_MyMigrationTest extends DatabaseMigrationTestCase {
/** #before */
public function prepare() {
$this->loadDump('2018-02-20');
$this->migrate('20180222232445');
}
public function testMigratedSomeData() {
$em = $this->container->get(EntityManagerInterface::class);
$someRow = $em->getConnection()->executeQuery('SELECT * FROM myTable WHERE id = 1')->fetch();
$this->assertEquals(1, $someRow['id']);
// check other stuff if it has been migrated correctly
}
}
I've figured out simple "smoke tests" for Doctrine Migrations.
I have PHPUnit test perfoming following steps:
Drop test DB
Create test DB
Load migrations (create schema)
Load fixtures (imitate production data)
Migrate to some older version
Migrate back to the latest version
This way I can test for the major issues, we've had recently.
Example of PHPUnit tests can be found on my blog: http://damiansromek.pl/2015/09/29/how-to-test-doctrine-migrations/
I'm learning MVC in PHP and using PDO for database access.
My database class is as follows (I use DEFINE in a config file for database variables):
class Database extends PDO {
public function __construct($dbconn ="mysql") {
$options = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING);
switch($dbconn) {
case 'usados':
parent::__construct(DB_TYPE_USADOS . ':host=' . DB_HOST_USADOS . ';dbname=' . DB_NAME_USADOS, DB_USER_USADOS, DB_PASS_USADOS, $options);
break;
case 'autos':
parent::__construct(DB_TYPE_AUTOS . ':host=' . DB_HOST_AUTOS . ';dbname=' . DB_NAME_AUTOS, DB_USER_AUTOS, DB_PASS_AUTOS, $options);
break;
case 'servicos':
parent::__construct(DB_TYPE_SERVICOS . ':host=' . DB_HOST_SERVICOS . ';dbname=' . DB_NAME_SERVICOS, DB_USER_SERVICOS, DB_PASS_SERVICOS, $options);
break;
default:
parent::__construct(DB_TYPE_MYSQL . ':host=' . DB_HOST_MYSQL . ';dbname=' . DB_NAME_MYSQL, DB_USER_MYSQL, DB_PASS_MYSQL, $options);
break;
}
}
}
And in an example model, I have:
class Note_Model extends Model {
public $errors = array();
public function __construct() {
parent::__construct($dbconn="mysql");
}
public function getAllNotes() {
$sth = $this->db->prepare("SELECT user_id, note_id, note_text
FROM note
WHERE user_id = :user_id ;");
$sth->execute(array(':user_id' => $_SESSION['user_id']));
return $sth->fetchAll();
}
}
I have 2 questions:
In my database class, is my approach for different database connections (to be used by different models) ok? Is the switch structure well used for this situation and a variable with where to connect?
I can connect to different databases in different models, but how would I get data from different databases in 1 same model if I had the need. Say for example, in a dashboard that shows information from different sources. It's not just $this->db, is it?
Thank you in advanced.
A switch statement in a constructor is a code smell indicating the class is doing too much. I'd create 4 classes (extending PDO or your own base class) and use them instead.
Regarding models, I'm no expert in MVC, but I know you can join tables in different databases provided they're on the same server. However, that could lead to a 'boss' class that breaks the one-database-per-class rule. The best way is probably to have another class that ask whatever models you need for data, and then pieces it together.
I want to use symfony2+doctrine2 for a new project. I ran into a little issue with postgresql-schemes. In contrast to mysql you can specify in postgres (like other databases) different schemes. Our productiv database has around 200 schemes for example.
I have to set a schema for my current doctrine connection. How can I do that?
I solved this issue a few months ago in another project, that uses doctrine2 only. I did the following:
$em = Doctrine\ORM\EntityManager::create($connectionOptions, $config);
$em->getConnection()->exec('SET SEARCH_PATH TO foobar');
But I dont know where I should do that in symfony2?
you could try to implement and use your own driver_class and pass the search_path in the PDO DriverOptions, e.g. in your symfony config:
# Doctrine Configuration
doctrine:
dbal:
driver: pdo_pgsql
driver_class: YourNamespace\YourBundle\Doctrine\DBAL\Driver\PDOPgSql\Driver
options:
search_path: YOUR_SEARCH_PATH
The driver could look something like this:
namespace YourNamespace\YourBundle\Doctrine\DBAL\Driver\PDOPgSql;
use Doctrine\DBAL\Platforms;
class Driver extends \Doctrine\DBAL\Driver\PDOPgSql\Driver implements \Doctrine\DBAL\Driver
{
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
{
// ADD SOME ERROR HANDLING WHEN THE SEARCH_PATH IS MISSING...
$searchPath = $driverOptions['search_path'];
unset($driverOptions['search_path']);
$connection = new \Doctrine\DBAL\Driver\PDOConnection(
$this->_constructPdoDsn($params),
$username,
$password,
$driverOptions
);
$connection->exec("SET SEARCH_PATH TO {$searchPath};");
return $connection;
}
/**
* Constructs the Postgres PDO DSN.
*
* #return string The DSN.
*/
protected function _constructPdoDsn(array $params)
{
$dsn = 'pgsql:';
if (isset($params['host']) && $params['host'] != '') {
$dsn .= 'host=' . $params['host'] . ' ';
}
if (isset($params['port']) && $params['port'] != '') {
$dsn .= 'port=' . $params['port'] . ' ';
}
if (isset($params['dbname'])) {
$dsn .= 'dbname=' . $params['dbname'] . ' ';
}
return $dsn;
}
}
You need the _constructPdoDsn method because it isn't defined as protected in \Doctrine\DBAL\Driver\PDOPgSql\Driver. It's bit "hacky" because we are using PDO DriverOptions and i'm not sure if that's a good way - but it seems to work.
Hope this helps.
Best regards,
Patryk
Since Doctrine 2.5 you can specify the schema name in the #Table annotation:
/**
* Clerk
*
* #Table(schema="schema")
*/
class Clerk { }
The only downside is, the symfony console can't do that, you have to specify it by hand.
Is there a simple way to log to queries to a file? I have Firebug profiling working no problem with:
resources.db.params.profiler.enabled = "true"
resources.db.params.profiler.class = "Zend_Db_Profiler_Firebug"
It would be nice to log this to a file with out writing a bunch of code.
Is there a class I can swap out with Zend_Db_Profiler_Firebug?
UPDATE: See my answer below.
As of ZF 1.11.11 there is no built in profiler class that will log queries to a file. Currently, FireBug is the only specialized Db Profiler.
Here are two ways in which you can solve it without loads of extra code though.
First, check out this answer as it shows how to extend Zend_Db_Profiler to have it log the queries to a file on queryEnd. If it doesn't quite do what you want, you can extend Zend_Db_Profiler and use the provided code as a starting point.
This next example is a slight modification of a plugin I have in some of my applications that I use to profile queries when the application is in development. This method utilizes a dispatchLoopShutdown() plugin to get an instance of the Db Profiler and log the queries to a file.
<?php /* library/My/Page/DbLogger.php */
class My_Page_DbLogger extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopShutdown()
{
$db = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('db');
$profiler = $db->getProfiler();
if ($profiler === NULL || !($profiler instanceof Zend_Db_Profiler))
return;
// either create your logger here based on config in application.ini
// or create it elsewhere and store it in the registry
$logger = Zend_Registry::get('dblog');
$totalQueries = $profiler->getTotalNumQueries();
$queryTime = $profiler->getTotalElapsedSecs();
$longestTime = 0;
$queries = $profiler->getQueryProfiles();
if ($queries !== false) {
$content = "\nExecuted $totalQueries database queries in $queryTime seconds<br />\n";
foreach ($queries as $query) {
// TODO: You could use custom logic here to log only selected queries
$content .= "Query (" . $query->getElapsedSecs() . "s): " . $query->getQuery() . "\n";
if ($query->getElapsedSecs() > $longestTime) {
$longestTime = $query->getElapsedSecs();
}
}
$content .= "Longest query time: $longestTime.\n" . str_repeat('-', 80);
$logger->info($content);
}
}
}
To activate this plugin, you can use code like this in your bootstrap:
/**
* Register the profiler if we are running in a non-production mode
*/
protected function _initPageProfiler()
{
if (APPLICATION_ENV == 'development') {
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new My_Page_DbLogger());
}
}
Ideally, in the long term, you would probably want to make a class that extends Zend_Db_Profiler and allow additional options to be specified in your config such as the log file path, the log priority. This way you can leverage the existing filters to Zend_Db_Profiler.
I'm writing a WordPress plug-in and need to read the database name, username, and password (In order to do a sql dump). Is this possible?
Thanks-
Yes, they are defined in wp-config.php
Database Name: DB_NAME
Database User: DB_USER
Database password: DB_PASSWORD
Database Host: DB_HOST
They are define. See you wp-config.php in the root directory of Wordpress
Wordpress has some fairly goofy stuff going on throughout its OO code, this isn't the first one I've encountered as we dig deeper into the internals with each successive project at Moxune. See WP_User::__set doesn't persist custom fields as it claims.
The goofiness I refer to here of course is that something like the table prefix, aka wpdb::prefix is a public member variable, however things like dbname, dbpassword, and dbhost are protected and there are no public accessor methods.
I'm sure one of the Wordpress core devs will try to argue some rationale for it, but in the meantime may as well use some good 'ol OO to cope. My suggestion, a decorator.
class SaneDb
{
private $_oDb;
public function __construct(wpdb $oDb)
{
$this->_oDb = $oDb;
}
public function __get($sField)
{
if($sField != '_oDb')
return $this->_oDb->$sField;
}
public function __set($sField, $mValue)
{
if($sField != '_oDb')
$this->_oDb->$sField = $mValue;
}
public function __call($sMethod, array $aArgs)
{
return call_user_func_array(array($this->_oDb, $sMethod), $aArgs);
}
public function getDbName() { return $this->_oDb->dbname; }
public function getDbPass() { return $this->_oDb->dbpassword; }
public function getDbHost() { return $this->_oDb->dbhost; }
}
Then atop your plugin code (functions.php) setup a global in similar vein to wpdb.
global $sanedb;
$sanedb = new SaneDb($wpdb);
From there, just use $sanedb within your plugin instead of $wpdb.
Lastly, getting ahold of the database name et al.
$sanedb->getDbName();
This is super simple now. You can create a PHP file and use the following code.
$path = $_SERVER['DOCUMENT_ROOT'];
include_once $path . '/wp-config.php';
include_once $path . '/wp-load.php';
include_once $path . '/wp-includes/wp-db.php';
include_once $path . '/wp-includes/pluggable.php';
// We need the WordPress Database Credentials
global $wpdb;
$user = $wpdb->dbuser;
$pass = $wpdb->dbpassword;
$name = $wpdb->dbname;
If you need other data just do a print_r on the wpdb variable and you'll see everything inside of there.