Version 5 supported

Basic usage

The Link model can be used with a has_one or has_many relation, depending on whether you want one or multiple links.

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 for more information about these methods.

The LinkField form field is used to manage links in a has_one relation, and MultiLinkField is for links in a has_many relation.

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

Adding the relationship(s) to the $owns configuration property is required for versioning (publishing) to work correctly. See 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 and 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. This is important for the permission model to work correctly.

namespace App\Model;

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. 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 validator:

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

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

// 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 above.

See versioning for more information about the implications of making this change.