Skip to content

Commit 6daf5c6

Browse files
committed
Initial test coverage. Not 100% but catches most of it. #1532 #1531
1 parent 07392e5 commit 6daf5c6

6 files changed

Lines changed: 472 additions & 33 deletions

File tree

system/Common.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ function config(string $name, bool $getShared = true)
123123
*
124124
* @return \CodeIgniter\Database\BaseConnection
125125
*/
126-
function db_connect($db, bool $getShared = true)
126+
function db_connect($db = null, bool $getShared = true)
127127
{
128128
return \Config\Database::connect($db, $getShared);
129129
}

system/Database/MigrationRunner.php

Lines changed: 102 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,37 @@ class MigrationRunner
126126
*/
127127
protected $cliMessages = [];
128128

129+
/**
130+
* Tracks whether we have already ensured
131+
* the table exists or not.
132+
*
133+
* @var boolean
134+
*/
135+
protected $tableChecked = false;
136+
137+
/**
138+
* The full path to locate migration files.
139+
*
140+
* @var string
141+
*/
142+
protected $path;
143+
129144
//--------------------------------------------------------------------
130145

131146
/**
132147
* Constructor.
133148
*
134-
* @param BaseConfig $config
135-
* @param \CodeIgniter\Database\ConnectionInterface $db
149+
* When passing in $db, you may pass any of the following to connect:
150+
* - group name
151+
* - existing connection instance
152+
* - array of database configuration values
153+
*
154+
* @param BaseConfig $config
155+
* @param \CodeIgniter\Database\ConnectionInterface|array|string $db
136156
*
137157
* @throws ConfigException
138158
*/
139-
public function __construct(BaseConfig $config, ConnectionInterface $db = null)
159+
public function __construct(BaseConfig $config, $db = null)
140160
{
141161
$this->enabled = $config->enabled ?? false;
142162
$this->type = $config->type ?? 'timestamp';
@@ -147,15 +167,10 @@ public function __construct(BaseConfig $config, ConnectionInterface $db = null)
147167
$this->namespace = APP_NAMESPACE;
148168

149169
// get default database group
150-
$config = new \Config\Database();
170+
$config = config('Database');
151171
$this->group = $config->defaultGroup;
152172
unset($config);
153173

154-
if (empty($this->table))
155-
{
156-
throw ConfigException::forMissingMigrationsTable();
157-
}
158-
159174
if (! in_array($this->type, ['sequential', 'timestamp']))
160175
{
161176
throw ConfigException::forInvalidMigrationType($this->type);
@@ -166,9 +181,7 @@ public function __construct(BaseConfig $config, ConnectionInterface $db = null)
166181

167182
// If no db connection passed in, use
168183
// default database group.
169-
$this->db = ! empty($db) ? $db : \Config\Database::connect();
170-
171-
$this->ensureTable();
184+
$this->db = db_connect($db);
172185
}
173186

174187
//--------------------------------------------------------------------
@@ -192,6 +205,9 @@ public function version(string $targetVersion, string $namespace = null, string
192205
{
193206
throw ConfigException::forDisabledMigrations();
194207
}
208+
209+
$this->ensureTable();
210+
195211
// Set Namespace if not null
196212
if (! is_null($namespace))
197213
{
@@ -204,6 +220,12 @@ public function version(string $targetVersion, string $namespace = null, string
204220
$this->setGroup($group);
205221
}
206222

223+
// Sequential versions need adjusting to 3 places so they can be found later.
224+
if ($this->type === 'sequential')
225+
{
226+
$targetVersion = str_pad($targetVersion, 3, '0', STR_PAD_LEFT);
227+
}
228+
207229
$migrations = $this->findMigrations();
208230

209231
if (empty($migrations))
@@ -284,6 +306,8 @@ public function version(string $targetVersion, string $namespace = null, string
284306
*/
285307
public function latest(string $namespace = null, string $group = null)
286308
{
309+
$this->ensureTable();
310+
287311
// Set Namespace if not null
288312
if (! is_null($namespace))
289313
{
@@ -315,6 +339,8 @@ public function latest(string $namespace = null, string $group = null)
315339
*/
316340
public function latestAll(string $group = null)
317341
{
342+
$this->ensureTable();
343+
318344
// Set database group if not null
319345
if (! is_null($group))
320346
{
@@ -361,6 +387,8 @@ public function latestAll(string $group = null)
361387
*/
362388
public function current(string $group = null)
363389
{
390+
$this->ensureTable();
391+
364392
// Set database group if not null
365393
if (! is_null($group))
366394
{
@@ -380,18 +408,39 @@ public function current(string $group = null)
380408
public function findMigrations()
381409
{
382410
$migrations = [];
383-
// Get namespace location form PSR4 paths.
384-
$config = new Autoload();
411+
helper('filesystem');
385412

386-
$location = $config->psr4[$this->namespace];
413+
// If $this->path contains a valid directory use it.
414+
if (! empty($this->path))
415+
{
416+
$dir = rtrim($this->path, DIRECTORY_SEPARATOR) . '/';
417+
}
418+
// Otherwise, get namespace location form PSR4 paths
419+
// and add Database/Migrations for a standard loation.
420+
else
421+
{
422+
$config = config('Autoload');
387423

388-
// Setting migration directories.
389-
$dir = rtrim($location, DIRECTORY_SEPARATOR) . '/Database/Migrations/';
424+
$location = $config->psr4[$this->namespace];
425+
426+
// Setting migration directories.
427+
$dir = rtrim($location, DIRECTORY_SEPARATOR) . '/Database/Migrations/';
428+
}
390429

391430
// Load all *_*.php files in the migrations path
392-
foreach (glob($dir . '*_*.php') as $file)
431+
// We can't use glob if we want it to be testable....
432+
$files = get_filenames($dir, true);
433+
434+
foreach ($files as $file)
393435
{
436+
if (substr($file, -4) !== '.php')
437+
{
438+
continue;
439+
}
440+
441+
// Remove the extension
394442
$name = basename($file, '.php');
443+
395444
// Filter out non-migration files
396445
if (preg_match($this->regex, $name))
397446
{
@@ -400,7 +449,9 @@ public function findMigrations()
400449
// Get migration version number
401450
$migration->version = $this->getMigrationNumber($name);
402451
$migration->name = $this->getMigrationName($name);
403-
$migration->path = $file;
452+
$migration->path = strpos($file, $this->path) !== 0
453+
? $this->path . $file
454+
: $file;
404455

405456
// Add to migrations[version]
406457
$migrations[$migration->version] = $migration;
@@ -436,7 +487,7 @@ protected function checkMigrations(array $migrations, string $method, string $ta
436487
}
437488

438489
// Check if $targetversion file is found
439-
if ($targetversion !== '0' && ! array_key_exists($targetversion, $migrations))
490+
if ((int)$targetversion !== 0 && ! array_key_exists($targetversion, $migrations))
440491
{
441492
if ($this->silent)
442493
{
@@ -458,14 +509,14 @@ protected function checkMigrations(array $migrations, string $method, string $ta
458509
{
459510
if ($this->type === 'sequential' && abs($migration->version - $loop) > 1)
460511
{
461-
throw new \RuntimeException(lang('Migration.gap') . ' ' . $migration->version);
512+
throw new \RuntimeException(lang('Migrations.gap') . ' ' . $migration->version);
462513
}
463514
// Check if all old migration files are all available to do downgrading
464515
if ($method === 'down')
465516
{
466517
if ($loop <= $history_size && $history_migrations[$loop]['version'] !== $migration->version)
467518
{
468-
throw new \RuntimeException(lang('Migration.gap') . ' ' . $migration->version);
519+
throw new \RuntimeException(lang('Migrations.gap') . ' ' . $migration->version);
469520
}
470521
}
471522
$loop ++;
@@ -476,6 +527,22 @@ protected function checkMigrations(array $migrations, string $method, string $ta
476527

477528
//--------------------------------------------------------------------
478529

530+
/**
531+
* Sets the path to the base directory that will be used
532+
* when locating migrations. If left null, the value will
533+
* be chosen from $this->namespace's directory.
534+
*
535+
* @param string|null $path
536+
*
537+
* @return $this
538+
*/
539+
public function setPath(string $path = null)
540+
{
541+
$this->path = $path;
542+
543+
return $this;
544+
}
545+
479546
/**
480547
* Set namespace.
481548
* Allows other scripts to modify on the fly as needed.
@@ -514,10 +581,14 @@ public function setGroup(string $group)
514581
* Set migration Name.
515582
*
516583
* @param string $name
584+
*
585+
* @return \CodeIgniter\Database\MigrationRunner
517586
*/
518587
public function setName(string $name)
519588
{
520589
$this->name = $name;
590+
591+
return $this;
521592
}
522593

523594
//--------------------------------------------------------------------
@@ -531,6 +602,8 @@ public function setName(string $name)
531602
*/
532603
public function getHistory(string $group = 'default')
533604
{
605+
$this->ensureTable();
606+
534607
$query = $this->db->table($this->table)
535608
->where('group', $group)
536609
->where('namespace', $this->namespace)
@@ -602,6 +675,8 @@ protected function getMigrationName(string $migration)
602675
*/
603676
protected function getVersion()
604677
{
678+
$this->ensureTable();
679+
605680
$row = $this->db->table($this->table)
606681
->select('version')
607682
->where('group', $this->group)
@@ -675,14 +750,14 @@ protected function removeHistory(string $version)
675750
* Ensures that we have created our migrations table
676751
* in the database.
677752
*/
678-
protected function ensureTable()
753+
public function ensureTable()
679754
{
680-
if ($this->db->tableExists($this->table))
755+
if ($this->tableChecked || $this->db->tableExists($this->table))
681756
{
682757
return;
683758
}
684759

685-
$forge = \Config\Database::forge();
760+
$forge = \Config\Database::forge($this->db);
686761

687762
$forge->addField([
688763
'version' => [
@@ -713,6 +788,8 @@ protected function ensureTable()
713788
]);
714789

715790
$forge->createTable($this->table, true);
791+
792+
$this->tableChecked = true;
716793
}
717794

718795
//--------------------------------------------------------------------

system/Exceptions/ConfigException.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ class ConfigException extends CriticalError
1414
*/
1515
protected $code = 3;
1616

17-
public static function forMissingMigrationsTable()
18-
{
19-
throw new static(lang('Migrations.missingTable'));
20-
}
21-
2217
public static function forInvalidMigrationType(string $type = null)
2318
{
2419
throw new static(lang('Migrations.invalidType', [$type]));
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php namespace App\Database\Migrations;
2+
3+
class Migration_some_migration extends \CodeIgniter\Database\Migration
4+
{
5+
public function up()
6+
{
7+
$this->forge->addField([
8+
'key' => [
9+
'type' => 'VARCHAR',
10+
'constraint' => 255,
11+
],
12+
]);
13+
$this->forge->createTable('foo', true);
14+
15+
$this->db->table('foo')->insert([
16+
'key' => 'foobar',
17+
]);
18+
}
19+
20+
public function down()
21+
{
22+
$this->forge->dropTable('foo');
23+
}
24+
}

tests/system/Database/Live/ConnectTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
<?php namespace CodeIgniter\Database\Live;;
1+
<?php namespace CodeIgniter\Database\Live;
2+
3+
;
24

35
use CodeIgniter\Config\Config;
46
use CodeIgniter\Test\CIDatabaseTestCase;
@@ -58,7 +60,7 @@ public function testConnectWorksWithGroupName()
5860
$db = Database::connect('tests');
5961
$this->assertInstanceOf(\CodeIgniter\Database\SQLite3\Connection::class, $db);
6062

61-
$config = config('Database');
63+
$config = config('Database');
6264
$config->default['DBDriver'] = 'MySQLi';
6365
Config::injectMock('Database', $config);
6466

0 commit comments

Comments
 (0)