Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW LinkableMigrationTask for migrating sheadawson-lin kable links #261

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method classIsOldLink have been removed as redundant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this been tested with the gorriecoe migration task to make sure it doesn't cause problems there?

}
Loading
Loading