Skip to content

Commit

Permalink
DOC Provide proper developer documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Feb 15, 2024
1 parent 58bd7a7 commit 93fa304
Show file tree
Hide file tree
Showing 9 changed files with 443 additions and 239 deletions.
236 changes: 2 additions & 234 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,238 +17,6 @@ This module provides a Link model and CMS interface for managing different types
composer require silverstripe/linkfield
```

## Sample usage
## Documentation

```php
<?php
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\LinkField\ORM\DBLink;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Form\LinkField;
use SilverStripe\LinkField\Form\MultiLinkField;

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

private static $has_many = [
// Multiple has_many relations on the same class should point at the same has_one on Link.
'HasManyLinksOne' => Link::class . '.Owner',
'HasManyLinksTwo' => Link::class . '.Owner',
];

private static array $owns = [
'HasOneLink',
'HasManyLinksOne',
'HasManyLinksTwo',
];

private static array $cascade_deletes = [
'HasOneLink',
'HasManyLinksOne',
'HasManyLinksTwo',
];

private static array $cascade_duplicates = [
'HasOneLink',
'HasManyLinksOne',
'HasManyLinksTwo',
];

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

// Don't forget to remove the auto-scaffolded fields!
$fields->removeByName(['HasOneLinkID', 'HasManyLinksOne', 'HasManyLinksTwo']);

$fields->addFieldsToTab(
'Root.Main',
[
LinkField::create('HasOneLink'),
MultiLinkField::create('HasManyLinksOne'),
MultiLinkField::create('HasManyLinksTwo'),
],
);

return $fields;
}
}
```

Adding the relationship(s) to the `$owns`, `$cascade_deletes`, and `$cascade_duplicates` config properties is required for versioning (publishing) to work correctly.

## Default title for each link type

By default, if the title for the link has not been set, then the default title will be used instead according to the type of link that is used. Default link is not stored in the database as link title. This value is used only when rendering page content.

The default title value can be updated using an `Extension` with an `updateDefaultLinkTitle()` method and applying that extension to a subclass of `Link`.

```php
// app/src/ExternalLinkExtension.php

namespace App\Extensions;

use SilverStripe\Core\Extension;

class ExternalLinkExtension extends Extension
{
public function updateDefaultLinkTitle(&$defaultLinkTitle): void
{
$defaultLinkTitle = sprintf('External link: %s', $this->owner->ExternalUrl);
}
}
```

## Controlling what type of links can be created in a LinkField

By default, all `Link` subclasses can be created by a `LinkField`. This includes any custom `Link` subclasses defined in your project or via a third party module.

If you wish to globally disable one of the default `Link` subclasses for all `LinkField` instances, then this can be done using the following YAML configuration with the FQCN (Fully-Qualified Class Name) of the relevant default `Link` subclass you wish to disable:

```yml
SilverStripe\LinkField\Models\SiteTreeLink:
allowed_by_default: false
```
You can also apply this configuration to any of your own custom `Link` subclasses:

```php
namespace App\Links;
use SilverStripe\LinkField\Models\Link;
class MyCustomLink extends Link
{
// ...
private static bool $allowed_by_default = false;
}
```

Developers can control the link types allowed for individual `LinkField`. The `setAllowedTypes()` method only allow link types that have been provided as parameters. This method will override the `allowed_by_default` configuration.

```php
$fields->addFieldsToTab(
'Root.Main',
[
LinkField::create('EmailLink')
->setAllowedTypes([EmailLink::class]),
MultiLinkField::create('PageLinkList')
->setAllowedTypes([SiteTreeLink::class, EmailLink::class]),
],
);
```

## Excluding the `LinkText` field

Sometimes you might want to have a link which doesn't have text, or for which you handle the text elsewhere. For example you might have a banner with a link, and you only want to use `LinkField` to control where the banner links to.

You can call the `setExcludeLinkTextField()` method to remove the `LinkText` field from the link modal for all links connected to that link field.

```php
$fields->addFieldsToTab(
'Root.Main',
[
MultiLinkField::create('LinkList')
->setExcludeLinkTextField(true),
Link::create('Link')
->setExcludeLinkTextField(true),
],
);
```

## Unversioned links

The `Link` model has the `Versioned` extension applied to it by default. If you wish for links to not be versioned, then remove the extension from the `Link` model in the projects `app/_config.php` file.

```php
// app/_config.php
use SilverStripe\LinkField\Models\Link;
use SilverStripe\Versioned\Versioned;
Link::remove_extension(Versioned::class);
```

## Additional features

The developer can customise the position of the link type in the menu by setting the `$menu_priority` value. The priority is in ascending order (i.e. a link with a higher priority value will be displayed lower in the list).

The developer can also set an icon that will correspond to a specific type of link by setting the value of the `$icon` configuration property. The value of this configuration corresponds to the css class of the icon to be used.

```yml
SilverStripe\LinkField\Models\PhoneLink:
icon: 'font-icon-menu-help'
menu_priority: 1
```

The developer can also define these values for a new link type.

```php
<?php
use SilverStripe\LinkField\Models\Link;
class MyCustomLink extends Link
{
private static int $menu_priority = 1;
private static $icon = 'font-icon-custom';
}
```

## Custom link validation

Custom links can have validation set using standard [model validation](https://docs.silverstripe.org/en/5/developer_guides/forms/validation/#model-validation).

## Automatic publishing of linked pages and files

When publishing a link that is either a "Page on this site" or a "Link to a file", the page or file that is linked to will not be automatically published when the link is published. This is to prevent unintentional publishing of draft or modified pages and files. However this does mean that content authors may publish links to unpublished pages or files which will return a 404 when a regular user attempts to use the link.

The link is itself published when the link's "owner" is published. The links owner is a page or another `DataObject` that the link has been added to as a relation.

If you wish to have pages and files that are linked to be automatically published when the link is published, then add the following YAML configuration in your project:

```yml
# "Page on this site"
SilverStripe\LinkField\Models\SiteTreeLink:
owns:
- Page
# "Link to a file"
SilverStripe\LinkField\Models\FileLink:
owns:
- File
```

Read more about [defining ownership between related objects](https://docs.silverstripe.org/en/5/developer_guides/model/versioning/#defining-ownership-between-related-versioned-dataobject-models).

## Migration from LinkField v3 to v4

The `Title` DB field has been renamed to `LinkText`

You can manually rename this column in your database with the following code:

```php
// app/_config.php
use SilverStripe\LinkField\Models\Link;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
// Only run this once
// This will rename the `Title` database column to `LinkText` in all relevant tables
$linkTable = DataObject::getSchema()->baseDataTable(Link::class);
DB::get_conn()->getSchemaManager()->renameField($linkTable, 'Title', 'LinkText');
```

It's recommended to put this code in a `BuildTask` so that you can run it exactly once, and then remove that code in a future deployment.

## 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.

* [Migration docs](docs/en/linkable-migration.md)
See [the official documentation](https://userhelp.silverstripe.org/en/optional_features/linkfield)
150 changes: 150 additions & 0 deletions docs/en/01_basic_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
---
title: Basic usage
summary: How to set up your link relations and fields
---

# Basic usage

The [`Link`](api:SilverStripe\LinkField\Models\Link) model can be used with a `has_one` or `has_many` relation, depending on whether you want one or multiple links.

> [!WARNING]
> Using `many_many` relations with the `Link` model is not supported. The `can*` permission methods on `Link` rely on having a single owner record they can inherit permissions from.
>
> See [model-level permissions](https://docs.silverstripe.org/en/developer_guides/model/permissions) for more information about these methods.
The [`LinkField`](api:SilverStripe\LinkField\Form\LinkField) form field is used to manage links in a `has_one` relation, and [`MultiLinkField`](api:SilverStripe\LinkField\Form\MultiLinkField) is for links in a `has_many` relation.

```php
namespace App\Model;

use SilverStripe\LinkField\Form\LinkField;
use SilverStripe\LinkField\Form\MultiLinkField;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\ORM\DataObject;

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

private static $has_many = [
'HasManyLinks' => Link::class . '.Owner',
];

private static array $owns = [
'HasOneLink',
'HasManyLinks',
];

private static array $cascade_deletes = [
'HasOneLink',
'HasManyLinks',
];

private static array $cascade_duplicates = [
'HasOneLink',
'HasManyLinks',
];

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

// Don't forget to remove the auto-scaffolded fields!
$fields->removeByName(['HasOneLinkID', 'HasManyLinks']);

$fields->addFieldsToTab(
'Root.Main',
[
LinkField::create('HasOneLink'),
MultiLinkField::create('HasManyLinks'),
],
);

return $fields;
}
}
```

> [!CAUTION]
> Adding the relationship(s) to the `$owns` configuration property is required for versioning (publishing) to work correctly. See [cascade publishing](https://docs.silverstripe.org/en/developer_guides/model/versioning/#cascade-publishing) to learn more.
The `$cascade_deletes` and `$cascade_duplicates` configuration is optional but beneficial. Without applying `$cascade_deletes` for example, deleting the parent record (a `MyModel` record in the example above) will result in orphaned links which are still in your database but not owned by anything. See [cascading deletions](https://docs.silverstripe.org/en/developer_guides/model/relations/#cascading-deletions) and [cascading duplications](https://docs.silverstripe.org/en/developer_guides/model/relations/#cascading-duplications) for more information.

## Multiple `has_many` relations on the same model

If you have multiple `has_many` relations on the same class, they should all point at the "Owner" `has_one` relation on `Link` using [dot notation](https://docs.silverstripe.org/en/developer_guides/model/relations/#dot-notation). This is important for the permission model to work correctly.

```php
namespace App\Model;

use SilverStripe\LinkField\Form\LinkField;
use SilverStripe\LinkField\Form\MultiLinkField;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\ORM\DataObject;

class MyModel extends DataObject
{
private static $has_many = [
'HasManyLinksOne' => Link::class . '.Owner',
'HasManyLinksTwo' => Link::class . '.Owner',
];
// ...
}
```

## Validation

Custom links can have validation set using standard [model validation](https://docs.silverstripe.org/en/developer_guides/forms/validation/#model-validation). This is true both for the validation of the link data itself, as well as validating relations to the `Link` class.

For example you can make sure you have a link in your `has_one` or `has_many` relation using a [`RequiredFields`](api:SilverStripe\Forms\RequiredFields) validator:

```php
namespace App\Model;

use SilverStripe\Forms\CompositeValidator;
use SilverStripe\Forms\RequiredFields;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\ORM\DataObject;

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

private static $has_many = [
'HasManyLinks' => Link::class . '.Owner',
];

// ...

public function getCMSCompositeValidator(): CompositeValidator
{
$validator = parent::getCMSCompositeValidator();
$validator->addValidator(RequiredFields::create(['HasOneLink', 'HasManyLinks']));
return $validator;
}
}
```

> [!TIP]
> You can also update validation logic of a given `Link` class by creating an `Extension` and implementing the `updateCMSCompositeValidator()` method.
## Unversioned links

The `Link` model has the [`Versioned`](api:SilverStripe\Versioned\Versioned) extension applied to it by default. If you wish for links to not be versioned, then remove the extension from the `Link` model in the project's `app/_config.php` file.

```php
// app/_config.php

use SilverStripe\LinkField\Models\Link;
use SilverStripe\Versioned\Versioned;

Link::remove_extension(Versioned::class);
```

If you do this, you don't need to apply the `$owns` configuration described in [basic usage](#basic-usage) above.

See [versioning](https://docs.silverstripe.org/en/developer_guides/model/versioning/) for more information about the implications of making this change.
Loading

0 comments on commit 93fa304

Please sign in to comment.