Skip to content

Commit

Permalink
4.next - Add base seed (#760)
Browse files Browse the repository at this point in the history
This class will be the new base class for Migrations that are compatible
with only the built-in backend. This gives a opt-in flow to having
a fully compatible migration set before the breaking change is done.

* Fix up table() interface and add integration test
* Expand coverage with an integration test.
* Add another assertion
* Fix usage of keywords
  • Loading branch information
markstory authored Oct 26, 2024
1 parent ef65019 commit 8681b80
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/AbstractSeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
* Class AbstractSeed
* Extends Phinx base AbstractSeed class in order to extend the features the seed class
* offers.
*
* @deprecated 4.5.0 You should use Migrations\BaseSeed for new seeds.
*/
abstract class AbstractSeed extends BaseAbstractSeed
{
Expand Down
235 changes: 235 additions & 0 deletions src/BaseSeed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
<?php
declare(strict_types=1);

/**
* MIT License
* For full license information, please view the LICENSE file that was distributed with this source code.
*/

namespace Migrations;

use Cake\Console\ConsoleIo;
use Migrations\Config\ConfigInterface;
use Migrations\Db\Adapter\AdapterInterface;
use Migrations\Db\Table;
use Migrations\Migration\ManagerFactory;
use RuntimeException;
use function Cake\Core\pluginSplit;

/**
* Base seed implementation
*
* Provides base functionality for seeds to extend.
*/
class BaseSeed implements SeedInterface
{
protected ?AdapterInterface $adapter = null;
protected ?ConsoleIo $io = null;
protected ?ConfigInterface $config;

/**
* No-op constructor.
*/
public function __construct()
{
}

/**
* {@inheritDoc}
*/
public function run(): void
{
}

/**
* {@inheritDoc}
*/
public function getDependencies(): array
{
return [];
}

/**
* {@inheritDoc}
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;

return $this;
}

/**
* {@inheritDoc}
*/
public function getAdapter(): AdapterInterface
{
if (!$this->adapter) {
throw new RuntimeException('Adapter not set.');
}

return $this->adapter;
}

/**
* {@inheritDoc}
*/
public function setIo(ConsoleIo $io)
{
$this->io = $io;

return $this;
}

/**
* {@inheritDoc}
*/
public function getIo(): ?ConsoleIo
{
return $this->io;
}

/**
* {@inheritDoc}
*/
public function getConfig(): ?ConfigInterface
{
return $this->config;
}

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

return $this;
}

/**
* {@inheritDoc}
*/
public function getName(): string
{
return static::class;
}

/**
* {@inheritDoc}
*/
public function execute(string $sql, array $params = []): int
{
return $this->getAdapter()->execute($sql, $params);
}

/**
* {@inheritDoc}
*/
public function query(string $sql, array $params = []): mixed
{
return $this->getAdapter()->query($sql, $params);
}

/**
* {@inheritDoc}
*/
public function fetchRow(string $sql): array|false
{
return $this->getAdapter()->fetchRow($sql);
}

/**
* {@inheritDoc}
*/
public function fetchAll(string $sql): array
{
return $this->getAdapter()->fetchAll($sql);
}

/**
* {@inheritDoc}
*/
public function insert(string $tableName, array $data): void
{
// convert to table object
$table = new Table($tableName, [], $this->getAdapter());
$table->insert($data)->save();
}

/**
* {@inheritDoc}
*/
public function hasTable(string $tableName): bool
{
return $this->getAdapter()->hasTable($tableName);
}

/**
* {@inheritDoc}
*/
public function table(string $tableName, array $options = []): Table
{
return new Table($tableName, $options, $this->getAdapter());
}

/**
* {@inheritDoc}
*/
public function shouldExecute(): bool
{
return true;
}

/**
* {@inheritDoc}
*/
public function call(string $seeder, array $options = []): void
{
$io = $this->getIo();
assert($io !== null, 'Requires ConsoleIo');
$io->out('');
$io->out(
' ====' .
' <info>' . $seeder . ':</info>' .
' <comment>seeding</comment>'
);

$start = microtime(true);
$this->runCall($seeder, $options);
$end = microtime(true);

$io->out(
' ====' .
' <info>' . $seeder . ':</info>' .
' <comment>seeded' .
' ' . sprintf('%.4fs', $end - $start) . '</comment>'
);
$io->out('');
}

/**
* Calls another seeder from this seeder.
* It will load the Seed class you are calling and run it.
*
* @param string $seeder Name of the seeder to call from the current seed
* @param array $options The CLI options passed to ManagerFactory.
* @return void
*/
protected function runCall(string $seeder, array $options = []): void
{
[$pluginName, $seeder] = pluginSplit($seeder);
$adapter = $this->getAdapter();
$connection = $adapter->getConnection()->configName();

$factory = new ManagerFactory([
'plugin' => $options['plugin'] ?? $pluginName ?? null,
'source' => $options['source'] ?? null,
'connection' => $options['connection'] ?? $connection,
]);
$io = $this->getIo();
assert($io !== null, 'Missing ConsoleIo instance');
$manager = $factory->createManager($io);
$manager->seed($seeder);
}
}
5 changes: 3 additions & 2 deletions src/SeedInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public function hasTable(string $tableName): bool;
* @param array<string, mixed> $options Options
* @return \Migrations\Db\Table
*/
public function table(string $tableName, array $options): Table;
public function table(string $tableName, array $options = []): Table;

/**
* Checks to see if the seed should be executed.
Expand All @@ -180,7 +180,8 @@ public function shouldExecute(): bool;
* for instance to respect foreign key constraints.
*
* @param string $seeder Name of the seeder to call from the current seed
* @param array $options The CLI options for the seeder.
* @return void
*/
public function call(string $seeder): void;
public function call(string $seeder, array $options = []): void;
}
4 changes: 2 additions & 2 deletions src/Shim/SeedAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public function hasTable(string $tableName): bool
/**
* {@inheritDoc}
*/
public function table(string $tableName, array $options): Table
public function table(string $tableName, array $options = []): Table
{
throw new RuntimeException('Not implemented');
}
Expand All @@ -245,7 +245,7 @@ public function shouldExecute(): bool
/**
* {@inheritDoc}
*/
public function call(string $seeder): void
public function call(string $seeder, array $options = []): void
{
throw new RuntimeException('Not implemented');
}
Expand Down
19 changes: 19 additions & 0 deletions tests/TestCase/Command/SeedCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,25 @@ public function testSeederOne(): void
$this->assertEquals(1, $query->fetchColumn(0));
}

public function testSeederBaseSeed(): void
{
$this->createTables();
$this->exec('migrations seed -c test --source BaseSeeds --seed MigrationSeedNumbers');
$this->assertExitSuccess();
$this->assertOutputContains('MigrationSeedNumbers:</info> <comment>seeding');
$this->assertOutputContains('AnotherNumbersSeed:</info> <comment>seeding');
$this->assertOutputContains('radix=10');
$this->assertOutputContains('fetchRow=121');
$this->assertOutputContains('hasTable=1');
$this->assertOutputContains('fetchAll=121');
$this->assertOutputContains('All Done');

$connection = ConnectionManager::get('test');
$query = $connection->execute('SELECT COUNT(*) FROM numbers');
// Two seeders run == 2 rows
$this->assertEquals(2, $query->fetchColumn(0));
}

public function testSeederImplictAll(): void
{
$this->createTables();
Expand Down
45 changes: 45 additions & 0 deletions tests/test_app/config/BaseSeeds/MigrationSeedNumbers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

use Migrations\BaseSeed;

/**
* NumbersSeed seed.
*/
class MigrationSeedNumbers extends BaseSeed
{
/**
* Run Method.
*
* Write your database seeder using this method.
*
* More information on writing seeders is available here:
* https://book.cakephp.org/phinx/0/en/seeding.html
*/
public function run(): void
{
$data = [
[
'number' => '5',
'radix' => '10',
],
];

// Call various methods on the seeder for runtime checks
// and generate output to assert behavior with in an integration test.
$this->table('numbers');
$this->insert('numbers', $data);

$this->call('AnotherNumbersSeed', ['source' => 'AltSeeds']);

$io = $this->getIo();
$query = $this->query('SELECT radix FROM numbers');
$io->out('radix=' . $query->fetchColumn(0));

$row = $this->fetchRow('SELECT 121 as row_val');
$io->out('fetchRow=' . $row['row_val']);
$io->out('hasTable=' . $this->hasTable('numbers'));

$rows = $this->fetchAll('SELECT 121 as row_val');
$io->out('fetchAll=' . $rows[0]['row_val']);
}
}

0 comments on commit 8681b80

Please sign in to comment.