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

v2: Update namespace, dependencies. Add PhoneLink & migration task #54

Merged
merged 18 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 11 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
12 changes: 12 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

jobs:
ci:
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
with:
js: false
chrispenny marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 0 additions & 12 deletions .scrutinizer.yml

This file was deleted.

39 changes: 0 additions & 39 deletions .travis.yml

This file was deleted.

57 changes: 32 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,66 @@
# Silverstripe link module

Experimental module looking at how we could implement a link field and a link data object.
This module provides a Link model and CMS interface for managing different types of links. Including:

* Emails
* External links
* Links to pages within the CMS
* Links to assets within the CMS
* Phone numbers

## Installation

Installation via composer.

### Stable version (GraphQL v3)

`composer require silverstripe/linkfield 1.x-dev`

### Experimental version (GraphQL v4)
### GraphQL v4 - Silverstripe 4

`composer require silverstripe/linkfield 2.x-dev`
`composer require silverstripe/linkfield`

### Known issues
### GraphQL v3 - Silverstripe 4

You may need to add the repository URL into your `composer.json` via the `repositories` field (example below).

```json
"repositories": {
"silverstripe/linkfield": {
"type": "git",
"url": "https://github.com/silverstripe/silverstripe-linkfield.git"
}
},
```
`composer require silverstripe/linkfield:^1`

## Sample usage

```php
<?php
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Link\DBLink;
use SilverStripe\Link\Link;
use SilverStripe\Link\LinkField;
use SilverStripe\LinkField\DBLink;
use SilverStripe\LinkField\Link;
use SilverStripe\LinkField\LinkField;

class Page extends SiteTree
{
private static $db = [
private static array $db = [
'DbLink' => DBLink::class
];

private static $has_one = [
private static array $has_one = [
'HasOneLink' => Link::class,
];

public function getCMSFields()
{
$fields = parent::getCMSFields();

$fields->insertBefore('Title', LinkField::create('HasOneLink'));
$fields->insertBefore('Title', LinkField::create('DbLink'));
$fields->addFieldsToTab(
'Root.Main',
[
LinkField::create('HasOneLink'),
LinkField::create('DbLink'),
]
)

return $fields;
}
}
```

## Migrating from Shae Dawson's Linkable module

https://github.com/sheadawson/silverstripe-linkable

Shae Dawson's Linkable module was a much loved, and much used module. It is, unfortunately, no longer maintained. We
have provided some steps and tasks that we hope can be used to migrate your project from Linkable to LinkField.

* [Migraiton docs](docs/en/linkable-migration.md)
8 changes: 4 additions & 4 deletions _config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ Name: linkfield

SilverStripe\Admin\LeftAndMain:
extensions:
- SilverStripe\Link\Extensions\LeftAndMain
- SilverStripe\LinkField\Extensions\LeftAndMain

SilverStripe\Admin\ModalController:
extensions:
- SilverStripe\Link\Extensions\ModalController
- SilverStripe\LinkField\Extensions\ModalController

SilverStripe\Forms\TreeDropdownField:
extensions:
- SilverStripe\Link\Extensions\AjaxField
- SilverStripe\LinkField\Extensions\AjaxField

SilverStripe\CMS\Forms\AnchorSelectorField:
extensions:
- SilverStripe\Link\Extensions\AjaxField
- SilverStripe\LinkField\Extensions\AjaxField
13 changes: 8 additions & 5 deletions _config/types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@
Name: linkfield-types
---

SilverStripe\Link\Type\Registry:
SilverStripe\LinkField\Type\Registry:
types:
cms:
classname: SilverStripe\Link\Models\SiteTreeLink
classname: SilverStripe\LinkField\Models\SiteTreeLink
enabled: true
external:
classname: SilverStripe\Link\Models\ExternalLink
classname: SilverStripe\LinkField\Models\ExternalLink
enabled: true
file:
classname: SilverStripe\Link\Models\FileLink
classname: SilverStripe\LinkField\Models\FileLink
enabled: true
email:
classname: SilverStripe\Link\Models\EmailLink
classname: SilverStripe\LinkField\Models\EmailLink
enabled: true
phone:
classname: SilverStripe\LinkField\Models\PhoneLink
enabled: true
4 changes: 2 additions & 2 deletions _graphql/queries.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'readLinkDescription(dataStr: String!)':
type: LinkDescription
resolver: ['SilverStripe\Link\GraphQL\LinkDescriptionResolver', 'resolve']
resolver: ['SilverStripe\LinkField\GraphQL\LinkDescriptionResolver', 'resolve']
'readLinkTypes(keys: [ID])':
type: '[LinkType]'
resolver: ['SilverStripe\Link\GraphQL\LinkTypeResolver', 'resolve']
resolver: ['SilverStripe\LinkField\GraphQL\LinkTypeResolver', 'resolve']
14 changes: 6 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@
"description": "Add advanced link functionality to Silverstripe.",
"type": "silverstripe-vendormodule",
"require": {
"silverstripe/admin": "^1.8",
"silverstripe/cms": "^4.8",
"silverstripe/asset-admin": "^1.8",
"silverstripe/graphql": "^4.x-dev",
"silverstripe/vendor-plugin": "^1"
"php": "^7.4 || ^8",
"silverstripe/cms": "^4.11",
"silverstripe/graphql": "^4"
},
"require-dev": {
"sminnee/phpunit": "^5.7",
"silverstripe/recipe-testing": "^2",
"squizlabs/php_codesniffer": "^3"
},
"license": "BSD-3-Clause",
Expand All @@ -36,8 +34,8 @@
},
"autoload": {
"psr-4": {
"SilverStripe\\Link\\": "src/",
"SilverStripe\\Link\\Tests\\": "tests/php/"
"SilverStripe\\LinkField\\": "src/",
"SilverStripe\\LinkField\\Tests\\": "tests/php/"
}
},
"config": {
Expand Down
147 changes: 147 additions & 0 deletions docs/en/linkable-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Instructions

## Preamble

This migration process covers shifting data from the `Linkable` tables to the appropriate `LinkField` tables.

This does not cover usages of `EmbeddedObject` (at least, not at this time).

**Versioned:** If you have `Versioned` `Linkable`, then the expectation is that you will also `Version` `LinkField`. If
you have not `Versioned` `Linkable`, then the expectation is that you will **not** `Version` `LinkField`.

## Install Silvesrtripe Linkfield

Install the Silverstripe Linkfield module:

```bash
$ composer require silverstripe/linkfield 1.x-dev
```

Or if you would like the (experimental) GraphQL 4 version:

```bash
$ composer require silverstripe/linkfield 2.x-dev
```

Optionally, you can also remove the Linkable module (though, you might find it useful to keep around as a reference
while you are upgrading your code).

Do this step at whatever point makes sense to you.

```bash
$ composer remove sheadawson/silverstripe-linkable
```

## Replace app usages

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.

If you have used imports (`use` statements), then your first step might just be to search for `use [old];` and replace
with `use [new];` (since the class name references have not changed at all).

Old: `Sheadawson\Linkable\Models\Link`
New: `SilverStripe\LinkField\Models\Link`

Old: `Sheadawson\Linkable\Forms\LinkField`
New: `SilverStripe\LinkField\Form\LinkField`

If you have extensions, new fields, etc, then your replacements might need to be a bit more considered.

The other key (less easy to automate) thing that you'll need to update is that the old `LinkField` required you to
specify the related field with `ID` appended, whereas the new `LinkField` requires you to specify the field without
`ID` appended. EG.

Old: `LinkField::create('MyLinkID')`
New: `LinkField::create('MyLink')`

Search for instances of `LinkField::create` and `new LinkField`, and hopefully that should give you all of the places
where you need to update field name references.

### Configuration

Be sure to check how the old module classes are referenced in config `yml` files (eg: `app/_config`). Update
appropriately.

### Populate module

If you use the populate module, you will not be able to simply "replace" the namespace. Fixture definitions for the
new Linkfield module are quite different. There are entirely different models for different link types, whereas before
it was just a DB field to specify the type.

## Replace template usages

Before: You might have had references to `$LinkURL` or `$Link.LinkURL`.
After: These would need to be updated to `$URL` or `$Link.URL` respectively.

Before: `$OpenInNewWindow` or `$Link.OpenInNewWindow`.
After: `$OpenInNew` or `$Link.OpenInew` respectively.

Before: `$Link.TargetAttr` or `$TargetAttr` would output the appropriate `target="xx"`.
After: There is no direct replacement.

This is an area where you should spend some decent effort to make sure each implementation is outputting as you expect
it to. There may be more "handy" methods that Linkable provided that no longer exist (that we haven't covered above).

## Table structures

It's important to understand that we are going from a single table in Linkable to multiple tables in LinkField.

**Before:** We had 1 table with all data, and one of the field in there specified the type of the Link.
**Now:** We have 1 table for each type of Link, with a base `Link` table for all record.

## Specify any custom configuration

Have a look at `LinkableMigrationTask`. There are some configuration properties defined in there:

- `$link_mapping`
- `$email_mapping`
- `$external_mapping`
- `$file_mapping`
- `$phone_mapping`
- `$sitetree_mapping`

Each of these specifies how an original field from the `LinkableLink` table will map to one of the new LinkField tables.

If you previously had some custom fields that needed to be available across **all** Link types, then you're (probably)
going to add this as an extension on the (base) `Link` class. This is going to mean that the new fields will be added
to the `LinkField_Link` table. This means that you need to update the configuration for `$link_mapping` so that we
correctly migrate those field values into the `LinkField_Link` table.

If you had/have a field that you only want displayed on (say) SiteTree links, then you would want to add that extension
to `SiteTreeLink`. This would create new fields in the `LinkField_SiteTreeLink` table, which will mean you need to
also update the config for `$sitetree_mapping`.

It's important that you get the correct mappings to the correct tables.

### Linkable `has_one` to one of your other DataObjects

An example for the above [Specify any custom configuration](#specify-any-custom-configuration) would be that if one
of your DataObjects `has_many` `Link`. This would require there to be a `has_one` on `Link` back to your DataObject.

Let's say that our `Page` `has_many` `Link`:
```php
class Page extends SiteTree
{
private static array $has_many = [
'Links' => Link::class,
];
}
```

This would require a corresponding `has_one` on `Link`:
```yaml
Sheadawson\Linkable\Models\Link:
has_one:
ParentPage: Page
```

If we inspect the `LinkableLink` table, we'll see that there is a field called `ParentPageID`. We need to tell the
migration task about this field, and where it needs to migrate to.

Assuming you keep the same relationship name, you'll want to add the following `$link_mapping` configuration:
```yaml
SilverStripe\LinkField\Tasks\LinkableMigrationTask:
link_mapping:
ParentPageID: ParentPageID
```
Loading