Skip to content

Commit

Permalink
NEW Linkfield ownership
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Oct 9, 2023
1 parent 7a16b8b commit b8ff21d
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 1 deletion.
1 change: 0 additions & 1 deletion _config.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@

// Avoid creating global variables
call_user_func(function () {

});
4 changes: 4 additions & 0 deletions _config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ SilverStripe\CMS\Forms\AnchorSelectorField:
SilverStripe\LinkField\Form\FormFactory:
extensions:
- SilverStripe\LinkField\Extensions\FormFactoryExtension

SilverStripe\ORM\DataObject:
extensions:
- SilverStripe\LinkField\Extensions\DataObjectExtension
47 changes: 47 additions & 0 deletions src/Extensions/DataObjectExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace SilverStripe\LinkField\Extensions;

use SilverStripe\ORM\DataExtension;
use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Models\LinkArea;

class DataObjectExtension extends DataExtension
{
public function onAfterWrite(): void
{
// Using onAfterWrite instead of onBeforeWrite to ensure that $this->owner->ID is not zero when creating new objects
parent::onAfterWrite();
foreach ($this->owner->hasOne() as $relation => $relationClassName) {
$relationField = $relation . 'ID';
$relationID = $this->owner->$relationField;
if (!$relationID) {
continue;
}
if (!is_a($relationClassName, Link::class, true) && !is_a($relationClassName, LinkArea::class, true)) {
continue;
}
// skip for the has_one:LinkArea relation on Link
if (is_a($this->owner, Link::class) && $relation === 'LinkArea') {
continue;
}
$relationObj = $relationClassName::get()->byID($relationID);
if ($relationObj === null) {
// could throw an Exception here, though not sure how if user would be able to fix it
continue;
}
$doWrite = false;
if ($relationObj->OwnerID !== $this->owner->ID) {
$relationObj->OwnerID = $this->owner->ID;
$doWrite = true;
}
if ($relationObj->OwnerClassName !== $this->owner->ClassName) {
$relationObj->OwnerClassName = $this->owner->ClassName;
$doWrite = true;
}
if ($doWrite) {
$relationObj->write();
}
}
}
}
76 changes: 76 additions & 0 deletions src/Extensions/LinkObjectExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace SilverStripe\LinkField\Extensions;

use SilverStripe\LinkField\Models\Link;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\DataObject;

/**
* This is only intended to be added to Link and LinkArea
* Implemented as an extension rather than base class so it doesn't create an extra base table that needs to be joined
*/
class LinkObjectExtension extends DataExtension
{
private static array $db = [
'OwnerID' => 'Int',
'OwnerClassName' => 'Varchar',
];

public function canView($member = null)
{
return $this->canCheck('canView', $member);
}

public function canCreate($member = null)
{
return $this->canCheck('canCreate', $member);
}

public function canEdit($member = null)
{
return $this->canCheck('canEdit', $member);
}

public function canDelete($member = null)
{
return $this->canCheck('canDelete', $member);
}

private function canCheck(string $canMethod, $member)
{
if (!$member) {
$member = Security::getCurrentUser();
}
$extended = $this->extendedCan($canMethod, $member);
if ($extended !== null) {
return $extended;
}
$owner = $this->getOwningDataObject();
if ($owner) {
return $owner->$canMethod($member);
}
return parent::$canMethod($member);
}

private function getOwningDataObject(): ?DataObject
{
// Thismethod is not called getOwner() because of existing Extension::getOwner() method
//
// If this is a Link, and LinkArea is set on it return that
if (is_a($this->owner, Link::class, true)) {
$linkArea = $this->owner->LinkArea();
if ($linkArea && $linkArea->exists()) {
return $linkArea;
}
}
// Otherwise look for the ownerID + ownerClassName
// These are set in DataObjectExtension::onAfterWrite()
$ownerID = $this->owner->OwnerID;
$ownerClassName = $this->owner->OwnerClassName;
if ($ownerID === 0 || $ownerClassName === '') {
return null;
}
return $ownerClassName::get()->byID($ownerID);
}
}
12 changes: 12 additions & 0 deletions src/Models/Link.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\View\Requirements;
use SilverStripe\LinkField\Extensions\LinkObjectExtension;
use SilverStripe\Versioned\Versioned;
use SilverStripe\LinkField\Models\LinkArea;

/**
* A Link Data Object. This class should be a subclass, and you should never directly interact with a plain Link
Expand All @@ -33,6 +36,15 @@ class Link extends DataObject implements JsonData, Type
'OpenInNew' => 'Boolean',
];

private static array $has_one = [
'LinkArea' => LinkArea::class
];

private static array $extensions = [
Versioned::class,
LinkObjectExtension::class,
];

/**
* In-memory only property used to change link type
* This case is relevant for CMS edit form which doesn't use React driven UI
Expand Down
34 changes: 34 additions & 0 deletions src/Models/LinkArea.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace SilverStripe\LinkField\Models;

use SilverStripe\LinkField\Models\Link;
use SilverStripe\LinkField\Extensions\LinkObjectExtension;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;

class LinkArea extends DataObject
{
private static $table_name = 'LinkField_LinkArea';

private static array $has_many = [
'Links' => Link::class,
];

private static array $owns = [
'Links',
];

private static array $cascade_deletes = [
'Links',
];

private static array $cascade_duplicates = [
'Links',
];

private static array $extensions = [
Versioned::class,
LinkObjectExtension::class,
];
}

0 comments on commit b8ff21d

Please sign in to comment.