Skip to content

Commit

Permalink
NEW LinkableMigrationTask for migrating sheadawson-linkable links
Browse files Browse the repository at this point in the history
  • Loading branch information
Sabina Talipova committed Apr 12, 2024
1 parent 934479c commit 4d9c84f
Show file tree
Hide file tree
Showing 14 changed files with 1,583 additions and 556 deletions.
388 changes: 388 additions & 0 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
544 changes: 2 additions & 542 deletions src/Tasks/GorriecoeMigrationTask.php

Large diffs are not rendered by default.

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);
}
}
129 changes: 129 additions & 0 deletions src/Tasks/LinkableMigrationTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php declare(strict_types=1);

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.
*/
class LinkableMigrationTask extends BuildTask
{
use MigrationTaskTrait;
use ModuleMigrationTaskTrait;

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

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

protected $description = 'Migrate from sheadawson/silverstripe-linkable to silverstripe/linkfield';

/**
* Enable via YAML configuration if you need to run this task
*/
private static ?bool $is_enabled = false;

/**
* The number of links to process at once, for operations that operate on each link individually.
* Processing links in chunks reduces the chance of hitting memory limits.
* Set to null to process all links in a single chunk.
*/
private static ?int $chunk_size = 1000;

/**
* The name of the table for the Sheadawson\Linkable\Models\Link model.
*
* Configurable since it's such a generic name, there's a chance people configured
* it to something different to avoid collisions.
*/
private static string $old_link_table = 'LinkableLink';

/**
* Mapping for columns in the base link table.
* Doesn't include subclass columns - see link_type_columns
*/
private static array $base_link_columns = [
'OpenInNewWindow' => 'OpenInNew',
'Title' => 'LinkText',
];

/**
* Mapping for different types of links, including the class to map to and
* database column mappings.
*/
private static array $link_type_columns = [
'URL' => [
'class' => ExternalLink::class,
'fields' => [
'URL' => 'ExternalUrl',
],
],
'Email' => [
'class' => EmailLink::class,
'fields' => [
'Email' => 'Email',
],
],
'Phone' => [
'class' => PhoneLink::class,
'fields' => [
'Phone' => 'Phone',
],
],
'File' => [
'class' => FileLink::class,
'fields' => [
'FileID' => 'FileID',
],
],
'SiteTree' => [
'class' => SiteTreeLink::class,
'fields' => [
'SiteTreeID' => 'PageID',
],
],
];

/**
* Perform the actual data migration and publish links as appropriate
*/
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('-----------------');

$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;
}
Loading

0 comments on commit 4d9c84f

Please sign in to comment.