Skip to content

Commit

Permalink
Added config option to specify custom seeder template path to use (#2146
Browse files Browse the repository at this point in the history
)

* Added config option to specify custom seeder template path to use

* Fixed codestyle problems

* Fixed code review problems

* Update src/Phinx/Config/Config.php

Fixing Code-Review problems

Co-authored-by: Mark Scherer <dereuromark@users.noreply.github.com>

* Fixed code review problems

* Fixed code review problems

* Fixed code review problems

Co-authored-by: Mark Scherer <dereuromark@users.noreply.github.com>
  • Loading branch information
SunriseCoder and dereuromark authored Nov 25, 2022
1 parent e43964d commit f18dd21
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 5 deletions.
24 changes: 24 additions & 0 deletions docs/en/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,30 @@ setting ``seed_base_class`` in your config:
seed_base_class: MyMagicalSeeder
Custom Migration Template
-------------------------

Custom template for Migrations could be used either by defining template file path
in configuration file:

.. code-block:: yaml
templates:
file: src/templates/customMigrationTemplate.php
Custom Seeder Template
----------------------

Custom Seeder template could be used either by defining template file path
in configuration file:

.. code-block:: yaml
templates:
seedFile: src/templates/customSeederTemplate.php
Environments
------------

Expand Down
8 changes: 8 additions & 0 deletions src/Phinx/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -538,4 +538,12 @@ public function offsetUnset($id): void
{
unset($this->values[$id]);
}

/**
* @inheritdoc
*/
public function getSeedTemplateFile(): ?string
{
return $this->values['templates']['seedFile'] ?? null;
}
}
7 changes: 7 additions & 0 deletions src/Phinx/Config/ConfigInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,11 @@ public function getMigrationBaseClassName(bool $dropNamespace = true): string;
* @return string
*/
public function getSeedBaseClassName(bool $dropNamespace = true): string;

/**
* Get the seeder template file name or null if not set.
*
* @return string|null
*/
public function getSeedTemplateFile(): ?string;
}
13 changes: 12 additions & 1 deletion src/Phinx/Console/Command/SeedCreate.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int
));
}

// Command-line option must have higher priority than value from Config
$config = $this->getConfig();
if (is_null($altTemplate)) {
$altTemplate = $config->getSeedTemplateFile();
if (!is_null($altTemplate) && !is_file($altTemplate)) {
throw new InvalidArgumentException(sprintf(
'The template file `%s` from config does not exist',
$altTemplate
));
}
}

// Determine the appropriate mechanism to get the template
// Load the alternative template if it is defined.
$contents = file_get_contents($altTemplate ?: $this->getSeedTemplateFilename());

$config = $this->getConfig();
$namespace = $config instanceof NamespaceAwareInterface ? $config->getSeedNamespaceByPath($path) : null;
$classes = [
'$namespaceDefinition' => $namespace !== null ? ('namespace ' . $namespace . ';') : '',
Expand Down
65 changes: 65 additions & 0 deletions tests/Phinx/Config/ConfigSeedTemplatePathsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Test\Phinx\Config;

use Phinx\Config\Config;

/**
* Class ConfigSeedTemplatePathsTest
*
* @package Test\Phinx\Config
* @group config
* @covers \Phinx\Config\Config::getSeedTemplateFile
*/
class ConfigSeedTemplatePathsTest extends AbstractConfigTest
{
public function testTemplateAndPathAreSet()
{
$values = [
'paths' => [
'seeds' => '/test',
],
'templates' => [
'seedFile' => 'seedFilePath',
],
];

$config = new Config($values);

$actualValue = $config->getSeedTemplateFile();
$this->assertEquals('seedFilePath', $actualValue);
}

public function testTemplateIsSetButNoPath()
{
// Here is used another key just to keep the node 'template' not empty
$values = [
'paths' => [
'seeds' => '/test',
],
'templates' => [
'file' => 'migration_template_file',
],
];

$config = new Config($values);

$actualValue = $config->getSeedTemplateFile();
$this->assertNull($actualValue);
}

public function testNoCustomSeedTemplate()
{
$values = [
'paths' => [
'seeds' => '/test',
],
];
$config = new Config($values);

$actualValue = $config->getSeedTemplateFile();
$this->assertNull($actualValue);

$config->getSeedPaths();
}
}
116 changes: 112 additions & 4 deletions tests/Phinx/Console/Command/SeedCreateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@

class SeedCreateTest extends TestCase
{
/**
* @var array
*/
protected $configValues = [];

/**
* @var ConfigInterface|array
*/
Expand All @@ -34,7 +39,7 @@ protected function setUp(): void
{
TestUtils::recursiveRmdir(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'seeds');
mkdir(sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'seeds', 0777, true);
$this->config = new Config([
$this->configValues = [
'paths' => [
'migrations' => sys_get_temp_dir(),
'seeds' => sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'seeds',
Expand All @@ -51,7 +56,8 @@ protected function setUp(): void
'port' => 3006,
],
],
]);
];
$this->config = new Config($this->configValues);

$this->input = new ArrayInput([]);
$this->output = new StreamOutput(fopen('php://memory', 'a', false));
Expand Down Expand Up @@ -115,7 +121,7 @@ public function testExecuteWithInvalidClassName()
$this->assertSame(AbstractCommand::CODE_ERROR, $exitCode);
}

public function testAlternativeTemplate()
public function testAlternativeTemplateFromConsole()
{
$application = new PhinxApplication();
$application->add(new SeedCreate());
Expand Down Expand Up @@ -148,7 +154,7 @@ public function testAlternativeTemplate()
$this->assertStringEqualsFile($match['SeedFilename'], $expectedMigration, 'Failed to create seed file from template generator correctly.');
}

public function testAlternativeTemplateDoesntExist()
public function testAlternativeTemplateFromConsoleDoesntExist()
{
$application = new PhinxApplication();
$application->add(new SeedCreate());
Expand All @@ -175,4 +181,106 @@ public function testAlternativeTemplateDoesntExist()
$exitCode = $commandTester->execute($commandLine, ['decorated' => false]);
$this->assertSame(AbstractCommand::CODE_ERROR, $exitCode);
}

public function testAlternativeTemplateFromConfigOnly()
{
$application = new PhinxApplication();
$application->add(new SeedCreate());

/** @var SeedCreate $command */
$command = $application->find('seed:create');

$this->configValues['templates']['seedFile'] = __DIR__ . '/Templates/SimpleSeeder.templateFromConfig.php.dist';
$this->config = new Config($this->configValues);
/** @var Manager $managerStub mock the manager class */
$managerStub = $this->getMockBuilder(\Phinx\Migration\Manager::class)
->setConstructorArgs([$this->config, $this->input, $this->output])
->getMock();

$command->setConfig($this->config);
$command->setManager($managerStub);

$commandTester = new CommandTester($command);

$commandLine = ['command' => $command->getName(), 'name' => 'AltTemplate'];
$exitCode = $commandTester->execute($commandLine, ['decorated' => false]);
$this->assertSame(AbstractCommand::CODE_SUCCESS, $exitCode);

// Get output.
preg_match('`created (?P<SeedFilename>.*?)\s`', $commandTester->getDisplay(), $match);

// Was migration created?
$this->assertFileExists($match['SeedFilename'], 'Failed to create seed file from template generator');

// Does the migration match our expectation?
$expectedMigration = "useClassName Phinx\\Seed\\AbstractSeed / className {$commandLine['name']} / baseClassName AbstractSeed\n"
. "This file should be specified in config only, not in console runs\n";
$this->assertStringEqualsFile($match['SeedFilename'], $expectedMigration, 'Failed to create seed file from template generator correctly.');
}

public function testAlternativeTemplateFromConfigOnlyDoesntExist()
{
$application = new PhinxApplication();
$application->add(new SeedCreate());

/** @var SeedCreate $command */
$command = $application->find('seed:create');

$template = __DIR__ . '/Templates/SimpleSeeder.templateFromConfigNotExist.php.dist';
$this->configValues['templates']['seedFile'] = $template;
$this->config = new Config($this->configValues);
/** @var Manager $managerStub mock the manager class */
$managerStub = $this->getMockBuilder(\Phinx\Migration\Manager::class)
->setConstructorArgs([$this->config, $this->input, $this->output])
->getMock();

$command->setConfig($this->config);
$command->setManager($managerStub);

$commandTester = new CommandTester($command);

$commandLine = ['command' => $command->getName(), 'name' => 'AltTemplate'];

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The template file `' . $template . '` from config does not exist');

$exitCode = $commandTester->execute($commandLine, ['decorated' => false]);
$this->assertSame(AbstractCommand::CODE_ERROR, $exitCode);
}

public function testAlternativeTemplateFromConfigAndConsole()
{
$application = new PhinxApplication();
$application->add(new SeedCreate());

/** @var SeedCreate $command */
$command = $application->find('seed:create');

$this->configValues['templates']['seedFile'] = __DIR__ . '/Templates/SimpleSeeder.templateFromConfig.php.dist';
$this->config = new Config($this->configValues);
/** @var Manager $managerStub mock the manager class */
$managerStub = $this->getMockBuilder(\Phinx\Migration\Manager::class)
->setConstructorArgs([$this->config, $this->input, $this->output])
->getMock();

$command->setConfig($this->config);
$command->setManager($managerStub);

$commandTester = new CommandTester($command);

$commandLine = ['command' => $command->getName(), 'name' => 'AltTemplate', '--template' => __DIR__ . '/Templates/SimpleSeeder.template.php.dist'];
$exitCode = $commandTester->execute($commandLine, ['decorated' => false]);
$this->assertSame(AbstractCommand::CODE_SUCCESS, $exitCode);

// Get output.
preg_match('`created (?P<SeedFilename>.*?)\s`', $commandTester->getDisplay(), $match);

// Was migration created?
$this->assertFileExists($match['SeedFilename'], 'Failed to create seed file from template generator');

// Does the migration match our expectation?
// In this case we expect content of template from Console argument to have higher priority
$expectedMigration = "useClassName Phinx\\Seed\\AbstractSeed / className {$commandLine['name']} / baseClassName AbstractSeed\n";
$this->assertStringEqualsFile($match['SeedFilename'], $expectedMigration, 'Failed to create seed file from template generator correctly.');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
useClassName $useClassName / className $className / baseClassName $baseClassName
This file should be specified in config only, not in console runs

0 comments on commit f18dd21

Please sign in to comment.