-
Notifications
You must be signed in to change notification settings - Fork 96
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 Add an extension to dynamically generate edit URLs #1361
NEW Add an extension to dynamically generate edit URLs #1361
Conversation
62cf84c
to
1431dee
Compare
code/HasCanonicalEditLink.php
Outdated
/** | ||
* Get a link to edit this page in the CMS. | ||
*/ | ||
public function CMSEditLink(): string |
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.
File
already has CMSEditLink
method, would this be a problem when applied to e.g. Image or other class extending File
?
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.
I can't think of literally any reason someone would do that - but if they did, I'm pretty sure the trait implementation would take precedence.
code/HasCanonicalEditLink.php
Outdated
* If the canonical edit owner is a has_one relation, the class on the other end | ||
* of the relation must have a CMSEditLink() method. | ||
*/ | ||
trait HasCanonicalEditLink |
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.
I was out for a bit and may have missed it, but do we have a naming convention for traits?
I'm a proponent of suffixing the name with the type of class/construct it is, e.g. SomethingTrait
, PageController
, FieldExtension
etc. so it's immediately obvious what it is.
trait HasCanonicalEditLink | |
trait CanonicalEditLinkTrait |
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.
We do have quite a few traits already - some are suffixed with Trait
but the majority are not.
I think the fact that you declare it as a trait, and you use
it, make it abundantly clear it's a trait.
Extension
and Controller
are a bit different because those aren't built-in language structure things like a trait (we don't say SiteTreeClass
after all).
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.
Agree we shouldn't suffix Trait
on this one (even though I'd actually like it, I also like the Interface
suffix), because most of the code base doesn't suffix it
I don't like the use of the word Canonical
at all - it really should just be CMSEditLink
I had a look at different traits in the codebase to find a common naming convention, there isn't that much in the way of consistency.
The most common pattern I could find was just calling the trait the feature it implemented e.g.
- trait ImageManiputlation
- trait FlushScheduler
- trait FormMessage
The next most consistent, though less common one was the Configurable / Extensible / Injectable - though those are less "concrete" concepts than just the other traits that just bolt a feature on
This makes a couple of obvious candidates
- trait CMSEditLink
- trait CMSEditLinkable (weird IMO)
I think CMSEditLink
is the most non-horrible of the two
class MyClass
{
use CMSEditLink;
And I get a CMSEditLink()
method
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.
I'll rename the trait to CMSEditLink
1431dee
to
abc3fe5
Compare
I remember having issues not being able to get an edit link to objects in past so this would be a welcome addition, however I'm not sure if it should be a trait or somehow integrated more closely with |
Less (if any) overhead is the main benefit - but mostly it just didn't really occur to me to make this as an extension.
It has to be opt-in. There's no way to know the canonical parent of some arbitrary model. How would we differentiate between the 12 has_one relations and the 3 model admins that all have edit links for some record? |
I've renamed the trait to |
abc3fe5
to
9fbb42f
Compare
Steve and I have talked about this offline - I'll be converting this into an |
9fbb42f
to
a153fad
Compare
a153fad
to
ac803c2
Compare
fb1a370
to
9cedf3d
Compare
code/ModelAdmin.php
Outdated
if (is_numeric($k)) { | ||
$models[$v] = ['dataClass' => $v, 'title' => singleton($v)->i18n_plural_name()]; | ||
unset($models[$k]); | ||
// Custom tab url segment but no custom title | ||
} elseif (is_a($v, DataObject::class, true)) { | ||
$models[$k] = ['dataClass' => $v, 'title' => singleton($v)->i18n_plural_name()]; |
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.
This fix was needed for tests to go green.
ab2b181
to
fafd681
Compare
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.
Mostly naming stuff
Key thing that we missed when we merged #1360 was the method name ModelAdmin::getEditLinkForManagedDataObject - it should be getCMSEditLinkForManagedDataObject for consistency with the rest of the code base
A quick string search
vendor/silverstripe/**/*.php
"CMSEditLink(" - 33 results
"EditLink(" - 37 results
Of the "EditLink(" that weren't "CMSEditLink(":
"updateCMSEditLink(" - 1 result
"getFileEditLink(" - 3 results
So you'll also need to rename https://github.com/silverstripe/silverstripe-admin/blob/1/code/ModelAdmin.php#L230 in this PR as well
The other thing is the word "Canonical" is very confusing. Rename this to "CMSEdit" so that it's standard with everything else
I've left a bunch of recommended edits, though there's a large number of things that will need renaming e.g. the test files, docs, etc
&& $field->getConfig()->getComponentByType(GridFieldDetailForm::class); | ||
} | ||
|
||
private function constructLink(string $relation, int $id): string |
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.
private function constructLink(string $relation, int $id): string | |
private function constructCMSEditLink(string $relation, int $id): string |
code/CMSEditLinkExtension.php
Outdated
return Director::absoluteURL($relativeLink); | ||
} | ||
|
||
private function getLinkForRelation(array $componentConfig, DataObject $obj, string $reciprocalRelation, FieldList $fields): string |
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.
private function getLinkForRelation(array $componentConfig, DataObject $obj, string $reciprocalRelation, FieldList $fields): string | |
private function getCMSEditLinkForRelation(array $componentConfig, DataObject $obj, string $reciprocalRelation, FieldList $fields): string |
code/CMSEditLinkExtension.php
Outdated
* @throws LogicException if a link cannot be established | ||
* e.g. if the object is not in a has_many relation or not edited inside a GridField. | ||
*/ | ||
public function getEditLinkForManagedDataObject(DataObject $obj, string $reciprocalRelation): string |
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.
public function getEditLinkForManagedDataObject(DataObject $obj, string $reciprocalRelation): string | |
public function getCMSEditLinkForManagedDataObject(DataObject $obj, string $reciprocalRelation): string |
code/CMSEditLinkExtension.php
Outdated
*/ | ||
class CMSEditLinkExtension extends Extension | ||
{ | ||
private static string $canonical_edit_owner = ''; |
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.
private static string $canonical_edit_owner = ''; | |
private static string $cms_edit_owner = ''; |
code/CMSEditLinkExtension.php
Outdated
* | ||
* @return LeftAndMain|DataObject|null | ||
*/ | ||
public function getCanonicalEditOwner() |
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.
public function getCanonicalEditOwner() | |
public function getCMSEditOwner() |
code/CMSEditLinkExtension.php
Outdated
*/ | ||
public function CMSEditLink(): string | ||
{ | ||
$owner = $this->owner->getCanonicalEditOwner(); |
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.
$owner = $this->owner->getCanonicalEditOwner(); | |
$owner = $this->owner->getCMSEditOwner(); |
code/CMSEditLinkExtension.php
Outdated
return ''; | ||
} | ||
|
||
if (!$owner->hasMethod('getEditLinkForManagedDataObject')) { |
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.
if (!$owner->hasMethod('getEditLinkForManagedDataObject')) { | |
if (!$owner->hasMethod('getCMSEditLinkForManagedDataObject')) { |
code/CMSEditLinkExtension.php
Outdated
} | ||
|
||
if (!$owner->hasMethod('getEditLinkForManagedDataObject')) { | ||
throw new LogicException('The canonical owner must implement getEditLinkForManagedDataObject()'); |
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.
throw new LogicException('The canonical owner must implement getEditLinkForManagedDataObject()'); | |
throw new LogicException('The canonical owner must implement getCMSEditLinkForManagedDataObject()'); |
code/CMSEditLinkExtension.php
Outdated
if ($owner instanceof DataObject) { | ||
$relativeLink = $owner->getEditLinkForManagedDataObject($this->owner, $this->owner->config()->get('canonical_edit_owner')); | ||
} else { | ||
$relativeLink = $owner->getEditLinkForManagedDataObject($this->owner); |
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.
$relativeLink = $owner->getEditLinkForManagedDataObject($this->owner); | |
$relativeLink = $owner->getCMSEditLinkForManagedDataObject($this->owner); |
code/CMSEditLinkExtension.php
Outdated
|
||
private function constructLink(string $relation, int $id): string | ||
{ | ||
$ownerType = $this->owner->config()->get('canonical_edit_owner'); |
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.
$ownerType = $this->owner->config()->get('canonical_edit_owner'); | |
$ownerType = $this->owner->config()->get('cms_edit_owner'); |
"canonical" is correct in this context - e.g. the But I'll make that change to avoid peer review ping pong and to match the other changes where "canonical" was already changed. |
3d9d6a4
to
27c65cd
Compare
code/CMSEditLinkExtension.php
Outdated
} | ||
|
||
/** | ||
* Get a link to edit this page in the CMS. |
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.
* Get a link to edit this page in the CMS. | |
* Get a link to edit this DataObject in the CMS. |
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.
Updated
27c65cd
to
052ed99
Compare
code/CMSEditLinkExtension.php
Outdated
* | ||
* Note that the cms edit owner must implement a getCMSEditLinkForManagedDataObject() method. | ||
* | ||
* If the cms edit owner is a has_one relation, the class on the other end |
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.
* If the cms edit owner is a has_one relation, the class on the other end | |
* If the cms_edit_owner is a has_one relation, the class on the other end |
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.
done
code/CMSEditLinkExtension.php
Outdated
private static string $cms_edit_owner = ''; | ||
|
||
/** | ||
* Get the admin or DataObject which owns this object for CMS editing purposes. |
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.
* Get the admin or DataObject which owns this object for CMS editing purposes. | |
* Get the ModelAdmin, LeftAndMain or DataObject which owns this object for CMS editing purposes. |
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.
ModelAdmin is a LeftAndMain - and they're all admin. I'll make this change but it's super subjective.
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.
done
43affee
to
767db75
Compare
use SilverStripe\Dev\TestOnly; | ||
use SilverStripe\ORM\DataObject; | ||
|
||
class BelongsToModelAdmin extends DataObject implements TestOnly |
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.
Could you please rename this, it's not a "belongs_to" relationship, which is defined as the reciprocal of a has_one relationship when it's a 1-1 relations.
Also, it being suffixed with "ModelAdmin" confused me for a long time because I mistakenly thought it extended ModelAdmin
Even just calling this TestDataObject
would be an improvement
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.
That wouldn't be an improvement, it's a lot less descriptive. I'll rename it to something that doesn't contain "belongsto" or end with "modeladmin". But given this is a test object I don't see that it matters all that much what it's called.
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.
Done
'Nested' => NestedObject::class . '.Parent', | ||
'AnotherArbitraryRelation' => NestedObject::class . '.AnotherOfTheSameClass', | ||
'BasicNested' => BasicNestedObject::class, | ||
'PolyMorphic' => PolymorphicNestedObject::class, |
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.
'PolyMorphic' => PolymorphicNestedObject::class, | |
'Polymorphic' => PolymorphicNestedObject::class, |
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.
Done
767db75
to
b525ae2
Compare
Currently getting an edit link for an object is a bit of a pain - you have to generate a new link based on the predictable gridfield or other admin edit paths. This is partly improved by #1360 - but that still doesn't resolve the problem for nested setups (e.g. object in a page's gridfield).
NOTE
CI won't go green until #1360 is merged in as the new tests rely on
ModelAdmin
having agetEditLinkForManagedDataObject()
methodRelated issue