Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
10 changes: 10 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
# Auto detect text files and perform LF normalization
* text=auto
/tests export-ignore
/docs export-ignore
/.editorconfig export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/code-of-conduct.md export-ignore
/contributing.md export-ignore
/README.md export-ignore
/.scrutinizer.yml export-ignore
/.github export-ignore
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ vendor
/composer.lock
/vendor/
/public/
/.php-cs-fixer.cache
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ Check out [documentation](https://gorriecoe.github.io/silverstripe-link/en)

- [Gorrie Coe](https://github.com/gorriecoe)
- [Elliot Sawyer](https://github.com/elliot-sawyer)


7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@
"nswdpc/ci-files": "dev-v-4",
"phpstan/phpstan": "^2",
"phpunit/phpunit": "^11.5",
"rector/rector": "^2"
"rector/rector": "^2",
"phpstan/phpstan-phpunit": "^2"
},
"extra": {
"installer-name": "link"
},
"config": {
"allow-plugins": {
"composer/installers": true,
"silverstripe/vendor-plugin": true
"silverstripe/vendor-plugin": true,
"silverstripe/recipe-plugin": true,
"phpstan/extension-installer": true
}
},
"scripts": {
Expand Down
8 changes: 5 additions & 3 deletions src/extensions/AutomaticMarkupID.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

namespace gorriecoe\Link\Extensions;

use gorriecoe\Link\Models\Link;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Extension;

/**
* Add sitetree type to link field
*
* @package silverstripe-link
* @extends \SilverStripe\Core\Extension<static>
*/
class AutomaticMarkupID extends Extension
{
Expand All @@ -17,9 +19,9 @@ class AutomaticMarkupID extends Extension
*/
public function updateIDValue(&$id)
{
$owner = $this->owner;
if ($owner->Title) {
$id = Convert::raw2url($owner->Title);
$owner = $this->getOwner();
if (($owner instanceof Link) && $owner->Title) {
$id = Convert::raw2url($owner->Title ?? '');
}
}
}
9 changes: 5 additions & 4 deletions src/extensions/DBStringLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Adds methods to DBString to help manipulate the output suitable for links
*
* @package silverstripe-link
* @extends \SilverStripe\Core\Extension<(\SilverStripe\ORM\FieldType\DBString & static)>
*/
class DBStringLink extends Extension
{
Expand All @@ -18,7 +19,7 @@ class DBStringLink extends Extension
*/
public function LinkFriendly(): string
{
return Convert::raw2url($this->owner->value);
return Convert::raw2url($this->getOwner()->value ?? '');
}

/**
Expand All @@ -32,13 +33,13 @@ public function URLFriendly(): string
/**
* Provides string replace to allow phone number friendly urls
*/
public function PhoneFriendly(): string
public function PhoneFriendly(): ?Phone
{
$value = $this->owner->value;
$value = $this->getOwner()->value;
if ($value) {
return Phone::create($value);
} else {
return '';
return null;
}
}
}
25 changes: 13 additions & 12 deletions src/extensions/DefineableMarkupID.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace gorriecoe\Link\Extensions;

use gorriecoe\Link\Models\Link;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\Core\Extension;
Expand All @@ -11,51 +12,51 @@
* Add sitetree type to link field
*
* @package silverstripe-link
* @property ?string $IDCustomValue
* @extends \SilverStripe\Core\Extension<static>
*/
class DefineableMarkupID extends Extension
{
/**
* Database fields
* @var array
*/
private static $db = [
private static array $db = [
'IDCustomValue' => 'Text'
];

/**
* Update Fields
* @return FieldList
*/
public function updateCMSFields(FieldList $fields)
{
$owner = $this->owner;
$fields->addFieldToTab(
'Root.Main',
TextField::create(
'IDCustomValue',
_t(__CLASS__ . '.ID', 'ID')
_t(self::class . '.ID', 'ID')
)
->setDescription(_t(__CLASS__ . '.IDCUSTOMVALUE', 'Define an ID for the link. This is particularly useful for google tracking.'))
->setDescription(_t(self::class . '.IDCUSTOMVALUE', 'Define an ID for the link. This is particularly useful for google tracking.'))
);
return $fields;
}

/**
* Event handler called before writing to the database.
*/
public function onBeforeWrite()
{
$owner = $this->owner;
$owner->IDCustomValue = Convert::raw2url($owner->IDCustomValue);
$owner = $this->getOwner();
if ($owner instanceof Link) {
$owner->IDCustomValue = Convert::raw2url($owner->IDCustomValue ?? '');
}
}

/**
* Renders an HTML ID attribute for this link
*/
public function updateIDValue(&$id)
public function updateIDValue(&$id): void
{
$owner = $this->owner;
if ($owner->IDCustomValue) {
$owner = $this->getOwner();
if (($owner instanceof Link) && $owner->IDCustomValue) {
$id = $owner->IDCustomValue;
}
}
Expand Down
91 changes: 47 additions & 44 deletions src/extensions/LinkSiteTree.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

use gorriecoe\Link\Models\Link;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Config;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TreeDropdownField;
use SilverStripe\Forms\TextField;
use SilverStripe\Core\Extension;
use UncleCheese\DisplayLogic\Forms\Wrapper;

if(!class_exists(SiteTree::class)) {
if (!class_exists(SiteTree::class)) {
return;
}

Expand All @@ -20,124 +21,126 @@
* @package silverstripe-link
*
* @property int $SiteTreeID
* @property ?string $Anchor
* @method mixed SiteTree()
* @extends \SilverStripe\Core\Extension<static>
*/
class LinkSiteTree extends Extension
{
/**
* Database fields
* @var array
*/
private static $db = [
private static array $db = [
'Anchor' => 'Varchar(255)',
];

/**
* Has_one relationship
* @var array
*/
private static $has_one = [
private static array $has_one = [
// @phpstan-ignore class.notFound
'SiteTree' => SiteTree::class,
];

/**
* A map of object types that can be linked to
* Custom dataobjects can be added to this
*
* @var array
**/
private static $types = [
private static array $types = [
'SiteTree' => 'Page on this website',
];

/**
* Defines the label used in the sitetree dropdown.
* @param String $sitetree_field_label
* @param string $sitetree_field_label
*/
private static $sitetree_field_label = 'MenuTitle';
private static string $sitetree_field_label = 'MenuTitle';

/**
* Update Fields
* @param FieldList $fields
*/
public function updateCMSFields(FieldList $fields)
{
if(class_exists(SiteTree::class)) {
$owner = $this->owner;
$config = $owner->config();
$sitetree_field_label = $config->get('sitetree_field_label') ? : 'MenuTitle';
$owner = $this->getOwner();
if (class_exists(SiteTree::class) && ($owner instanceof Link)) {

$sitetree_field_label = Config::inst()->get($owner::class, 'sitetree_field_label') ?: 'MenuTitle';

// Insert site tree field after the file selection field
$fields->insertAfter(
'Type',
Wrapper::create(
$sitetreeField = TreeDropdownField::create(
'SiteTreeID',
_t(__CLASS__ . '.PAGE', 'Page'),
_t(self::class . '.PAGE', 'Page'),
SiteTree::class
)
->setTitleField($sitetree_field_label),
TextField::create(
'Anchor',
_t(__CLASS__ . '.ANCHOR', 'Anchor/Querystring')
_t(self::class . '.ANCHOR', 'Anchor/Querystring')
)
->setDescription(_t(__CLASS__ . '.ANCHORINFO', 'Include # at the start of your anchor name or, ? at the start of your querystring'))
->setDescription(_t(self::class . '.ANCHORINFO', 'Include # at the start of your anchor name or, ? at the start of your querystring'))
)
->displayIf('Type')->isEqualTo('SiteTree')->end()
);

// Display warning if the selected page is deleted or unpublished
if ($owner->SiteTreeID && !$owner->SiteTree()->isPublished()) {
$sitetreeField->setDescription(_t(__CLASS__ . '.DELETEDWARNING', 'Warning: The selected page appears to have been deleted or unpublished. This link may not appear or may be broken in the frontend'));
$siteTree = $owner->SiteTree();
if ($siteTree->isInDB() && !$siteTree->isPublished()) {
$sitetreeField->setDescription(_t(self::class . '.DELETEDWARNING', 'Warning: The selected page appears to have been deleted or unpublished. This link may not appear or may be broken in the frontend'));
}
}
}

public function updateIsCurrent(&$status): void
{
$owner = $this->owner;
$owner = $this->getOwner();
if (
class_exists(SiteTree::class) &&
$owner->Type == 'SiteTree' &&
isset($owner->SiteTreeID) &&
($owner->CurrentPage instanceof SiteTree)
($owner instanceof Link) &&
$owner->Type == 'SiteTree'
) {
$currentPage = $owner->CurrentPage;
$status = $currentPage === $owner->SiteTree() || $currentPage->ID === $owner->SiteTreeID;
$currentPage = $owner->getCurrentPage();
if ($currentPage instanceof SiteTree) {
$status = $currentPage === $owner->SiteTree() || $currentPage->ID === $owner->SiteTreeID;
}
}
}

public function updateIsSection(&$status): void
{
$owner = $this->owner;
$owner = $this->getOwner();
if (
class_exists(SiteTree::class) &&
$owner->Type == 'SiteTree' &&
isset($owner->SiteTreeID) &&
($owner->CurrentPage instanceof SiteTree)
($owner instanceof Link) &&
$owner->Type == 'SiteTree'
) {
$currentPage = $owner->CurrentPage;
$status = $owner->isCurrent() || in_array($owner->SiteTreeID, $currentPage->getAncestors()->column());
$currentPage = $owner->getCurrentPage();
if ($currentPage instanceof SiteTree) {
$status = $owner->isCurrent() || in_array($owner->SiteTreeID, $currentPage->getAncestors()->column());
}
}
}

public function updateIsOrphaned(&$status): void
{
$owner = $this->owner;
$owner = $this->getOwner();
if (
class_exists(SiteTree::class) &&
$owner->Type == 'SiteTree' &&
isset($owner->SiteTreeID) &&
($owner->CurrentPage instanceof SiteTree)
($owner instanceof Link) &&
$owner->Type == 'SiteTree'
) {
$currentPage = $owner->CurrentPage;
// Always false for root pages
if (empty($owner->SiteTree()->ParentID)) {
$status = false;
} else {
// Parent must exist and not be an orphan itself
$parent = $owner->Parent();
$status = !$parent || !$parent->exists() || $parent->isOrphaned();
$currentPage = $owner->getCurrentPage();
if ($currentPage instanceof SiteTree) {
// Always false for root pages
if (empty($owner->SiteTree()->ParentID)) {
$status = false;
} else {
// Parent must exist and not be an orphan itself
$parent = $owner->Parent();
$status = !$parent || !$parent->exists() || $parent->isOrphaned();
}
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/extensions/SiteTreeLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
namespace gorriecoe\Link\Extensions;

use gorriecoe\Link\Models\Link;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Extension;

/**
* Fixes duplicate link in SiteTree
*
* @package silverstripe-link
* @extends \SilverStripe\Core\Extension<static>
*/
class SiteTreeLink extends Extension
{
Expand All @@ -17,9 +20,9 @@ class SiteTreeLink extends Extension
*/
public function onBeforeDuplicate()
{
$owner = $this->owner;
$owner = $this->getOwner();
//loop through has_one relationships and reset any Link fields
if($hasOne = $owner->Config()->get('has_one')){
if (class_exists(SiteTree::class) && ($owner instanceof SiteTree) && ($hasOne = Config::inst()->get($owner::class, 'has_one'))) {
foreach ($hasOne as $field => $fieldType) {
if ($fieldType === Link::class) {
$owner->{$field.'ID'} = 0;
Expand Down
Loading