Skip to content

Commit

Permalink
Merge pull request #7 from itmundi/feature/migrations
Browse files Browse the repository at this point in the history
Automatically run new plugin migrations
  • Loading branch information
Bob Olde Hampsink committed Oct 22, 2015
2 parents 232d5d2 + 7904cdf commit c4bfc32
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ You can also generate a schema.yml with
```

## Hooks

* Has a hook "registerMigrationService" to add exports with your own data.

```php
Expand Down
18 changes: 10 additions & 8 deletions consolecommands/SchematicCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ public function actionImport($file = 'craft/config/schema.yml', $force = false)
{
if (!IOHelper::fileExists($file)) {
$this->usageError(Craft::t('File not found.'));
exit(1);
}

$result = craft()->schematic->importFromYaml($file, $force);

if (!$result->hasErrors()) {
echo Craft::t('Loaded schema from {file}', array('file' => $file))."\n";
exit(0);
SchematicPlugin::log(Craft::t('Loaded schema from {file}', array('file' => $file)));

return 0;
}

echo Craft::t('There was an error loading schema from {file}', array('file' => $file))."\n";
print_r($result->errors);
exit(1);
SchematicPlugin::log(Craft::t('There was an error loading schema from {file}', array('file' => $file)));
print_r($result->getErrors());

return 1;
}

/**
Expand All @@ -49,7 +50,8 @@ public function actionExport($file = 'craft/config/schema.yml')
{
craft()->schematic->exportToYaml($file);

echo Craft::t('Exported schema to {file}', array('file' => $file))."\n";
exit(0);
SchematicPlugin::log(Craft::t('Exported schema to {file}', array('file' => $file)));

return 0;
}
}
60 changes: 52 additions & 8 deletions services/Schematic_PluginsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,24 @@ protected function getPluginService()
}

/**
* Installs plugin by handle
* @return MigrationsService
*/
protected function getMigrationsService()
{
return craft()->migrations;
}

/**
* @return UpdatesService
*/
protected function getUpdatesService()
{
return craft()->updates;
}

/**
* Installs plugin by handle.
*
* @param string $handle
*/
protected function installPluginByHandle($handle)
Expand All @@ -37,7 +54,8 @@ protected function installPluginByHandle($handle)
}

/**
* Uninstalls plugin by handle
* Uninstalls plugin by handle.
*
* @param $handle
*/
protected function uninstallPluginByHandle($handle)
Expand All @@ -46,8 +64,10 @@ protected function uninstallPluginByHandle($handle)
}

/**
* Returns plugin by handle
* Returns plugin by handle.
*
* @param string $handle
*
* @return BasePlugin|null
*/
protected function getPlugin($handle)
Expand All @@ -61,9 +81,10 @@ protected function getPlugin($handle)
}

/**
* Toggles plugin based on enabled flag
* Toggles plugin based on enabled flag.
*
* @param string $handle
* @param bool $isEnabled
* @param bool $isEnabled
*/
protected function togglePluginByHandle($handle, $isEnabled)
{
Expand All @@ -75,29 +96,50 @@ protected function togglePluginByHandle($handle, $isEnabled)
}

/**
* Run plugin migrations automatically.
*
* @param BasePlugin $plugin
*/
protected function runMigrations(BasePlugin $plugin)
{
if (!$this->getMigrationsService()->runToTop($plugin)) {
throw new Exception(Craft::t('There was a problem updating your database.'));
}
if (!$this->getUpdatesService()->setNewPluginInfo($plugin)) {
throw new Exception(Craft::t('The update was performed successfully, but there was a problem setting the new info in the plugins table.'));
}
}

/**
* @param BasePlugin $plugin
*
* @return array
*/
private function getPluginDefinition(BasePlugin $plugin)
{
return array(
'isInstalled' => $plugin->isInstalled,
'isEnabled' => $plugin->isEnabled,
'settings' => $plugin->getSettings()->attributes
'settings' => $plugin->getSettings()->attributes,
);
}

/**
* @param array $pluginDefinitions
* @param bool $force
* @param bool $force
*
* @return Schematic_ResultModel
*/
public function import(array $pluginDefinitions, $force = false)
{
foreach ($pluginDefinitions as $handle => $pluginDefinition) {
if ($plugin = $this->getPlugin($handle)) {
if ($pluginDefinition['isInstalled']) {
$this->installPluginByHandle($handle);
if (!$plugin->isInstalled) {
$this->installPluginByHandle($handle);
} else {
$this->runMigrations($plugin);
}

$this->togglePluginByHandle($handle, $pluginDefinition['isEnabled']);

Expand All @@ -115,6 +157,7 @@ public function import(array $pluginDefinitions, $force = false)

/**
* @param array $data
*
* @return array
*/
public function export(array $data = array())
Expand All @@ -126,6 +169,7 @@ public function export(array $data = array())
$pluginDefinitions[$handle] = $this->getPluginDefinition($plugin);
}
ksort($pluginDefinitions);

return $pluginDefinitions;
}
}
83 changes: 65 additions & 18 deletions tests/Schematic_PluginsServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use PHPUnit_Framework_MockObject_MockObject as Mock;

/**
* Class Schematic_PluginsServiceTest
* Class Schematic_PluginsServiceTest.
*
* @author Itmundi
* @copyright Copyright (c) 2015, Itmundi
Expand Down Expand Up @@ -44,12 +44,31 @@ public static function setUpBeforeClass()
require_once __DIR__.'/../services/Schematic_PluginsService.php';
}

/**
* Prevent code duplication by mocking multiple services.
*
* @param bool $returnPlugin
* @param bool $installPluginResponse
*/
public function mockMultipleServices(
$returnPlugin = true,
$installPluginResponse = true
) {
$mockPluginsService = $this->getMockPluginsService($returnPlugin, $installPluginResponse);
$this->setComponent(craft(), 'plugins', $mockPluginsService);
$mockMigrationsService = $this->getMockMigrationsService();
$this->setComponent(craft(), 'migrations', $mockMigrationsService);
$mockUpdatesService = $this->getMockUpdatesService();
$this->setComponent(craft(), 'updates', $mockUpdatesService);
}

/**
* @param bool $returnPlugin
* @param bool $installPluginResponse
* @param bool $enablePluginResponse
* @param bool $disablePluginResponse
* @param bool $uninstallPluginResponse
*
* @return PluginsService|Mock
*/
public function getMockPluginsService(
Expand All @@ -63,7 +82,7 @@ public function getMockPluginsService(

$mock->expects($this->any())->method('getPlugin')->willReturn(($returnPlugin) ? $this->getMockBasePlugin() : null);

if($installPluginResponse) {
if ($installPluginResponse) {
$mock->expects($this->any())->method('installPlugin')->willReturn($installPluginResponse);
} else {
$mock->expects($this->any())->method('installPlugin')->willThrowException(new Exception());
Expand All @@ -76,6 +95,28 @@ public function getMockPluginsService(
return $mock;
}

/**
* @return MigrationsService|Mock
*/
public function getMockMigrationsService()
{
$mock = $this->getMockBuilder('Craft\MigrationsService')->getMock();
$mock->expects($this->any())->method('runToTop')->willReturn(true);

return $mock;
}

/**
* @return UpdatesService|Mock
*/
public function getMockUpdatesService()
{
$mock = $this->getMockBuilder('Craft\UpdatesService')->getMock();
$mock->expects($this->any())->method('setNewPluginInfo')->willReturn(true);

return $mock;
}

/**
* @return Mock|BasePlugin
*/
Expand All @@ -87,14 +128,15 @@ public function getMockBasePlugin()
}

/**
* Test default import functionality
* Test default import functionality.
*
* @covers ::import
*/
public function testImportWithInstalledPlugins()
{
$data = $this->getPluginsData();
$mockPluginsService = $this->getMockPluginsService();
$this->setComponent(craft(), 'plugins', $mockPluginsService);

$this->mockMultipleServices();

$import = $this->schematicPluginsService->import($data);

Expand All @@ -103,15 +145,16 @@ public function testImportWithInstalledPlugins()
}

/**
* Test default import functionality
* Test default import functionality.
*
* @covers ::import
*/
public function testImportWithInstalledDisabledPlugins()
{
$data = $this->getPluginsData();
$data['itmundiplugin']['isEnabled'] = false;
$mockPluginsService = $this->getMockPluginsService();
$this->setComponent(craft(), 'plugins', $mockPluginsService);

$this->mockMultipleServices();

$import = $this->schematicPluginsService->import($data);

Expand All @@ -120,7 +163,8 @@ public function testImportWithInstalledDisabledPlugins()
}

/**
* Test default import functionality
* Test default import functionality.
*
* @covers ::import
*/
public function testImportWithMissingPlugin()
Expand All @@ -137,15 +181,15 @@ public function testImportWithMissingPlugin()
}

/**
* Test default import functionality
* Test default import functionality.
*
* @covers ::import
*/
public function testImportWithInstallException()
{
$data = $this->getPluginsData();

$mockPluginsService = $this->getMockPluginsService(true, false);
$this->setComponent(craft(), 'plugins', $mockPluginsService);
$this->mockMultipleServices(true, false);

$import = $this->schematicPluginsService->import($data);

Expand All @@ -154,7 +198,8 @@ public function testImportWithInstallException()
}

/**
* Test default import functionality
* Test default import functionality.
*
* @covers ::import
*/
public function testImportWithNotInstalledPlugin()
Expand All @@ -172,7 +217,8 @@ public function testImportWithNotInstalledPlugin()
}

/**
* Test export functionality
* Test export functionality.
*
* @covers ::export
*/
public function testExport()
Expand All @@ -199,7 +245,8 @@ public function testExport()
}

/**
* Returns plugins data
* Returns plugins data.
*
* @return array
*/
public function getPluginsData()
Expand All @@ -211,9 +258,9 @@ public function getPluginsData()
'settings' => array(
'pluginName' => 'Menu',
'canDoActions' => '',
'quietErrors' => ''
)
)
'quietErrors' => '',
),
),
);
}
}

0 comments on commit c4bfc32

Please sign in to comment.