-
Notifications
You must be signed in to change notification settings - Fork 15
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
NEW Linkfield ownership #101
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,5 +5,4 @@ | |
|
||
// Avoid creating global variables | ||
call_user_func(function () { | ||
|
||
}); |
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; | ||||||||||
} | ||||||||||
Comment on lines
+24
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This extension shouldn't be applied directly to |
||||||||||
$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; | ||||||||||
} | ||||||||||
Comment on lines
+34
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like that we're essentially storing the has_one in two places in the DB here. We're really working around a fundamental limitation in framework.
All of the above do away with needing this extension altogether. |
||||||||||
if ($doWrite) { | ||||||||||
$relationObj->write(); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
} |
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 | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't make this an extension. If you want to share the can* methods just use a trait which is more performant. There's nothing here that needs to be in an extension. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The private static $db cannot be used as a trait, because it'll clash with the private static $db on Link. You'll get this error: PHP Fatal error: Link and LinkObjectTrait define the same property ($db) in the composition of Link. However, the definition differs and is considered incompatible. The Extension class is basically a heavier weight "Silverstripe trait" and will nicely merge private statics There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Correct. As suggested in #101 (comment) the |
||||||||||||||||
{ | ||||||||||||||||
private static array $db = [ | ||||||||||||||||
'OwnerID' => 'Int', | ||||||||||||||||
'OwnerClassName' => 'Varchar', | ||||||||||||||||
]; | ||||||||||||||||
Comment on lines
+15
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This creates the same db fields (but with the correct types, dbforeignkey and dbclassname) and gives us the ability to go This should be declared directly on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also should probably be |
||||||||||||||||
|
||||||||||||||||
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(); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
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); | ||||||||||||||||
} | ||||||||||||||||
Comment on lines
+56
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This won't be needed on On public function Owner()
{
$owner = $this->getComponent('Owner');
// If $owner is the LinkArea, return the underlying record that owns the area.
if ($owner instanceof LinkArea) {
$owner = $owner->Owner();
}
return $owner;
} Unfortunately we can't call this With this method, we can rely on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm not sure? The has_one is on an artibary DataObject (usually Page), so the LinkArea needs this as a way to find it's Owner/Parent?
Not if it's not using a LinkArea, and instead it's a has_one on an arbitary DataObject (usually Page). General idea for this PR was that it allows Links to be used as has_one's on Page's, or as has_many's via LinkArea's |
||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -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 | ||||||||||||||
|
@@ -33,6 +36,15 @@ class Link extends DataObject implements JsonData, Type | |||||||||||||
'OpenInNew' => 'Boolean', | ||||||||||||||
]; | ||||||||||||||
|
||||||||||||||
private static array $has_one = [ | ||||||||||||||
'LinkArea' => LinkArea::class | ||||||||||||||
]; | ||||||||||||||
Comment on lines
+39
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
As per above comments. Again, probably this should be |
||||||||||||||
|
||||||||||||||
private static array $extensions = [ | ||||||||||||||
Versioned::class, | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why versioned? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linked issue says "versioned operations" - you need to make Link Versioned to do versioned operations :-) |
||||||||||||||
LinkObjectExtension::class, | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Either add all the can* methods in here or apply them as a trait. |
||||||||||||||
]; | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* In-memory only property used to change link type | ||||||||||||||
* This case is relevant for CMS edit form which doesn't use React driven UI | ||||||||||||||
|
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, | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why versioned? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replied above on Link |
||||
LinkObjectExtension::class, | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Either add all the can* methods in here or apply them as a trait. |
||||
]; | ||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let people apply it themselves to any classes where they want to use links (the same way elemental doesn't apply its extension to
DataObject
or toSiteTree
by default).