Skip to content

Commit

Permalink
ENH Remove classIsOldLink method
Browse files Browse the repository at this point in the history
  • Loading branch information
Sabina Talipova committed Apr 11, 2024
1 parent 147260b commit 458b3cb
Show file tree
Hide file tree
Showing 12 changed files with 695 additions and 269 deletions.
439 changes: 335 additions & 104 deletions docs/en/09_migrating/01_linkable-migration.md

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/en/09_migrating/02_gorriecoe-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ composer require silverstripe/linkfield:^4

### Configure the migration task

> [!NOTE]
> Be sure to check how the old module classes are referenced in config `yml` files (eg: `app/_config`). Update appropriately.
1. Enable the task:

```yml
Expand Down Expand Up @@ -122,6 +125,8 @@ composer require silverstripe/linkfield:^4

### Update your codebase

You should review how you are using the original `Link` model and `LinkField`, but if you don't have any customisations, then replacing the old with the new might be quite simple.

1. If you added any database columns to the `Link` class for sorting `has_many` relations, or any `has_one` relations for storing them, remove the extension or YAML configuration for that now.

```diff
Expand Down Expand Up @@ -277,8 +282,8 @@ For databases that support transactions, the full data migration is performed wi
- via the browser: `https://www.example.com/dev/build?flush=1`
- via a terminal: `sake dev/build flush=1`
1. Run the task
- via the browser: `https://www.example.com/dev/tasks/linkfield-tov4-migration-task`
- via a terminal: `sake dev/tasks/linkfield-tov4-migration-task`
- via the browser: `https://www.example.com/dev/tasks/gorriecoe-to-linkfield-migration-task`
- via a terminal: `sake dev/tasks/gorriecoe-to-linkfield-migration-task`

The task performs the following steps:

Expand Down
93 changes: 29 additions & 64 deletions src/Tasks/GorriecoeMigrationTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,14 @@
namespace SilverStripe\LinkField\Tasks;

use RuntimeException;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Dev\BuildTask;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Models\EmailLink;
use SilverStripe\LinkField\Models\ExternalLink;
use SilverStripe\LinkField\Models\FileLink;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Models\PhoneLink;
use SilverStripe\LinkField\Models\SiteTreeLink;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\Queries\SQLDelete;
use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\ORM\Queries\SQLUpdate;
use SilverStripe\Versioned\Versioned;

/**
* @deprecated 4.0.0 Will be removed without equivalent functionality.
Expand Down Expand Up @@ -99,66 +93,37 @@ class GorriecoeMigrationTask extends BuildTask
];

/**
* List any has_many relations that should be migrated.
*
* Keys are the FQCN for the class where the has_many is declared.
* Values are the name of the old has_one.
*
* Example:
* <code>
* // SiteConfig had two has_many relationships,
* // one to Link.MyHasOne and another to Link.DifferentHasOne.
* SiteConfig::class => [
* 'LinksListOne' => 'MyHasOne',
* 'LinksListTwo' => 'DifferentHasOne',
* ]
* </code>
* Perform the actual data migration and publish links as appropriate
*/
private static array $has_many_links_data = [];
public function performMigration(): void
{
$this->extend('beforePerformMigration');
// Because we're using SQL INSERT with specific ID values,
// we can't perform the migration if there are existing links because there
// may be ID conflicts.
if (Link::get()->exists()) {
throw new RuntimeException('Cannot perform migration with existing silverstripe/linkfield link records.');
}

/**
* List any many_many relations that should be migrated.
*
* Keys are the FQCN for the class where the many_many is declared. See example below for values.
*
* Example:
* <code>
* // SiteConfig had three many_many relationships:
* // The table name for "LinksListOne" will be guessed. It wasn't a many_many through and had no extra fields
* // The table name for "LinksListTwo" will be guessed. It wasn't a many_many through but did have some extra fields
* // The table name for "LinksListThree" is explicitly provided. It was a many_many through with some extra fields
* SiteConfig::class => [
* 'LinksListOne' => null,
* 'LinksListTwo' => [
* 'extraFields' => [
* 'MySort' => 'Sort',
* ],
* ],
* 'LinksListThree' => [
* 'table' => 'App_MyThroughClassTable',
* 'extraFields' => [
* 'MySort' => 'Sort',
* ],
* 'through' => [
* 'from' => 'FromHasOneName',
* 'to' => 'ToHasOneName',
* ],
* ],
* ]
* </code>
*/
private static array $many_many_links_data = [];
$this->insertBaseRows();
$this->insertTypeSpecificRows();
$this->updateSiteTreeRows();
$this->migrateHasManyRelations();
$this->migrateManyManyRelations();
$this->setOwnerForHasOneLinks();

/**
* The table name for the base gorriecoe link model.
*/
private string $oldTableName;
$this->print("Dropping old link table '{$this->oldTableName}'");
DB::get_conn()->query("DROP TABLE \"{$this->oldTableName}\"");

/**
* The old link model class name
*/
private function classIsOldLink(string $class): bool
{
return $class === 'gorriecoe\Link\Models\Link';
$this->print('-----------------');
$this->print('Bulk data migration complete. All links should be correct (but unpublished) at this stage.');
$this->print('-----------------');

$this->publishLinks();

$this->print('-----------------');
$this->print('Migration completed successfully.');
$this->print('-----------------');
$this->extend('afterPerformMigration');
}
}
5 changes: 0 additions & 5 deletions src/Tasks/LinkFieldMigrationTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,4 @@ private function migrateHasManyRelations(): void
}
$this->extend('afterMigrateHasManyRelations');
}

private function classIsOldLink(string $class): bool
{
return is_a($class, Link::class, true);
}
}
58 changes: 36 additions & 22 deletions src/Tasks/LinkableMigrationTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace SilverStripe\LinkField\Tasks;

use RuntimeException;
use SilverStripe\Dev\BuildTask;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Models\EmailLink;
use SilverStripe\LinkField\Models\ExternalLink;
use SilverStripe\LinkField\Models\FileLink;
use SilverStripe\LinkField\Models\PhoneLink;
use SilverStripe\LinkField\Models\SiteTreeLink;
use SilverStripe\ORM\DB;

/**
* @deprecated 4.0.0 Will be removed without equivalent functionality.
Expand All @@ -17,7 +20,7 @@ class LinkableMigrationTask extends BuildTask
use MigrationTaskTrait;
use ModuleMigrationTaskTrait;

private static $segment = 'linkable-migration-task';
private static $segment = 'linkable-to-linkfield-migration-task';

protected $title = 'Linkable to Linkfield Migration Task';

Expand All @@ -26,7 +29,7 @@ class LinkableMigrationTask extends BuildTask
/**
* Enable via YAML configuration if you need to run this task
*/
private static ?bool $is_enabled = true;
private static ?bool $is_enabled = false;

/**
* The number of links to process at once, for operations that operate on each link individually.
Expand All @@ -45,7 +48,7 @@ class LinkableMigrationTask extends BuildTask

/**
* Mapping for columns in the base link table.
* Doesn't include
* Doesn't include subclass columns - see link_type_columns
*/
private static array $base_link_columns = [
'OpenInNewWindow' => 'OpenInNew',
Expand Down Expand Up @@ -90,26 +93,37 @@ class LinkableMigrationTask extends BuildTask
];

/**
* List any has_many relations that should be migrated.
* Perform the actual data migration and publish links as appropriate
*/
private static array $has_many_links_data = [];


/**
* List any many_many relations that should be migrated.
*/
private static array $many_many_links_data = [];

/**
* The table name for the base link model.
*/
private string $oldTableName;

/**
* The old link model class name
*/
private function classIsOldLink(string $class): bool
public function performMigration(): void
{
return $class === 'Sheadawson\Linkable\Models\Link';
$this->extend('beforePerformMigration');
// Because we're using SQL INSERT with specific ID values,
// we can't perform the migration if there are existing links because there
// may be ID conflicts.
if (Link::get()->exists()) {
throw new RuntimeException('Cannot perform migration with existing silverstripe/linkfield link records.');
}

$this->insertBaseRows();
$this->insertTypeSpecificRows();
$this->updateSiteTreeRows();
$this->migrateHasManyRelations();
$this->migrateManyManyRelations();
$this->setOwnerForHasOneLinks();

$this->print("Dropping old link table '{$this->oldTableName}'");
DB::get_conn()->query("DROP TABLE \"{$this->oldTableName}\"");

$this->print('-----------------');
$this->print('Bulk data migration complete. All links should be correct (but unpublished) at this stage.');
$this->print('-----------------');

$this->publishLinks();

$this->print('-----------------');
$this->print('Migration completed successfully.');
$this->print('-----------------');
$this->extend('afterPerformMigration');
}
}
7 changes: 1 addition & 6 deletions src/Tasks/MigrationTaskTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private function setOwnerForHasOneLinks(): void
}

// Skip if the has_one isn't for Link, or points at a belongs_to or has_many on Link
if (!$this->classIsOldLink($hasOneClass)) {
if (!is_a($hasOneClass, Link::class, true)) {
continue;
}
if ($this->hasReciprocalRelation([$hasOneClass], $hasOneName, $modelClass)) {
Expand Down Expand Up @@ -435,9 +435,4 @@ abstract public function performMigration(): void;
* Check if we actually need to migrate anything, and if not give clear output as to why not.
*/
abstract private function getNeedsMigration(): bool;

/**
* Returns true if the class represents an old link to be migrated
*/
abstract private function classIsOldLink(string $class): bool;
}
81 changes: 51 additions & 30 deletions src/Tasks/ModuleMigrationTaskTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,60 @@
trait ModuleMigrationTaskTrait
{
/**
* Perform the actual data migration and publish links as appropriate
* List any has_many relations that should be migrated.
*
* Keys are the FQCN for the class where the has_many is declared.
* Values are the name of the old has_one.
*
* Example:
* <code>
* // SiteConfig had two has_many relationships,
* // one to Link.MyHasOne and another to Link.DifferentHasOne.
* SiteConfig::class => [
* 'LinksListOne' => 'MyHasOne',
* 'LinksListTwo' => 'DifferentHasOne',
* ]
* </code>
*/
public function performMigration(): void
{
$this->extend('beforePerformMigration');
// Because we're using SQL INSERT with specific ID values,
// we can't perform the migration if there are existing links because there
// may be ID conflicts.
if (Link::get()->exists()) {
throw new RuntimeException('Cannot perform migration with existing silverstripe/linkfield link records.');
}

$this->insertBaseRows();
$this->insertTypeSpecificRows();
$this->updateSiteTreeRows();
$this->migrateHasManyRelations();
$this->migrateManyManyRelations();
$this->setOwnerForHasOneLinks();

$this->print("Dropping old link table '{$this->oldTableName}'");
DB::get_conn()->query("DROP TABLE \"{$this->oldTableName}\"");

$this->print('-----------------');
$this->print('Bulk data migration complete. All links should be correct (but unpublished) at this stage.');
$this->print('-----------------');
private static array $has_many_links_data = [];

$this->publishLinks();
/**
* List any many_many relations that should be migrated.
*
* Keys are the FQCN for the class where the many_many is declared. See example below for values.
*
* Example:
* <code>
* // SiteConfig had three many_many relationships:
* // The table name for "LinksListOne" will be guessed. It wasn't a many_many through and had no extra fields
* // The table name for "LinksListTwo" will be guessed. It wasn't a many_many through but did have some extra fields
* // The table name for "LinksListThree" is explicitly provided. It was a many_many through with some extra fields
* SiteConfig::class => [
* 'LinksListOne' => null,
* 'LinksListTwo' => [
* 'extraFields' => [
* 'MySort' => 'Sort',
* ],
* ],
* 'LinksListThree' => [
* 'table' => 'App_MyThroughClassTable',
* 'extraFields' => [
* 'MySort' => 'Sort',
* ],
* 'through' => [
* 'from' => 'FromHasOneName',
* 'to' => 'ToHasOneName',
* ],
* ],
* ]
* </code>
*/
private static array $many_many_links_data = [];

$this->print('-----------------');
$this->print('Migration completed successfully.');
$this->print('-----------------');
$this->extend('afterPerformMigration');
}
/**
* The table name for the base link model.
*/
private string $oldTableName;

/**
* Check if we actually need to migrate anything, and if not give clear output as to why not.
Expand Down
Loading

0 comments on commit 458b3cb

Please sign in to comment.