-
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
Initial review of linkfield #81
Comments
Link to my first look at the module which includes a list of maintenance tasks to perform Here I've had done a deeper look at the code. I've assumed that project implementations are done via adding the Feature gapsPermission checks
Validation
public function getCMSCompositeValidator(): CompositeValidator
{
$validator = parent::getCMSCompositeValidator();
$validator->addValidator(RequiredFields::create([
'Phone',
]));
return $validator;
} Versioning
Multiple links support in a single field
Internal slack convoInternal slack conversation asking developers about what they perceive as feature gaps - https://silverstripeltd.slack.com/archives/CLXKD9X51/p1695690436734529. tl;dr:
Code architecturePHP
Javascript
CSS
Documentation
Test coverage (phpunit, jest, behat)Unit testing
CI
Maintenance
Notes about the 2x implementationsDBLink:Faster database performance, though uses controversial JSON data in db field - makes finding data via DB queries much harder. We don't do this anywhere else in Silverstripe. private static array $db = [
'DbLink' => DBLink::class
];
Traditional has_one:Slower database performance as it needs to join a bunch of tables together, though consistent with the rest of Silverstripe private static array $has_one = [
'HasOneLink' => Link::class,
];
|
Questions that require further discussion
|
I'll add some extra limitations here. |
Broken links / TinyMCE are just making shortcodes in a That said maybe a leftfield idea here is to save everything in linkfield as shortcodes instead of DB Objects, and require any custom Link subclasses to define their own shortcodes |
Broken links are not shortcodes so I don't know what you meant by that part. TinyMCE links are stored in the DBHtmlField as shortcodes, and I would recommend that happen with an implementation that this module provides, as well. The shortcode would look something like
Shortcodes don't actually store data, really. Look at the "page on this site" shortcode for example: |
Note that that would not be MVP - I'd recommend we look at doing that as an enhancement down the line rather than as part of the initial epic. |
Ah yup you're right, sorry confused myself. From memory the broken links uses some pretty old and fragile code that at least partially uses SiteTreeLinkTracking to generate the report.
OK so you're saying there should be a central way to quickly work out which of all the internal/external Link records are broken?
So you could "Insert a link" in TinyMCE and select an email address (which you can do now), though you're saying that link would now get saved as a new DataObject and a shortcode inserted into the Content field, instead of what currently happens where it just gets turned straight into |
Yeah. My understanding is that the whole point of this module is that there's a single standardised way to manage links in the CMS. The WYSIWYG should not be excluded from that goal IMO. One very clear benefit being that a broken links report will "just work" - we wouldn't have to go through all HTML fields hunting for links, we can just do a Another advantage is that it makes it really easy to modify the way links display in a standardised way (e.g. adding an "external link" icon to all external links would be as simple as editing the link template).
Yup that's exactly what I'm proposing. |
I've created another issue here #84 with a bunch of linked draft PRs that implement a bunch (though not all) of what I've discussed on this issue plus more |
Every DataObject should have proper permission check out of the box. Whether we tie the permissions to an explicit owner for the link or to some pre-existing CMS permission, I'm not sure. But I don't consider the current status quo acceptable.
We should aim to have more than just a black and white validation. The LinkField is designed to be extensible with the expectation that you could provide more complex Link Type. e.g. The external link should have validation to make sure that the provided URL is a valid URL. The same way we use form schema to retrieve the form list, we could post back the data we got to see if it's valid. VersioningDo we want to versioned this by default? This introduces a dependency on versioned. Would we consider conditionally versioning link only if versioned is installed? There's also a related concern that if you are versioning Links, you need to make sure they get published when the parent record is published. Multiple links support in a single fieldAny field has some pretty solid support for "Has many" list. If we don't want to go all the way and jump on the AnyField band wagon right away, we can just copy its implementation. I agree that ManyMany support is a bad idea. Links should be strongly tied to a parent ... the same way that an Elemental block is tightly coupled to an Elemental Area. Internal slack convo
AnyField has that capability. Once you dump the registry idea and the need to register link classes up front, this becomes pretty easy.
I like this idea. I could image a link shortcode that gets managed in a similar way to a link field. However, this sounds more like a nice to have than something we should aim to support right away. Code architecturePHP
Agree
ModalController is equivalent to RemoteFileModalExtension The LeftAndMain extension is just working around the fact that there's no "LinkAdmin" controller to host some endpoints. Asset-admin doesn't have that problem because it has its own controller. FormFactory is something @mfendeksilverstripe created: #65 . Not sure why he didn't directly update FormFactory. AjaxField is working around a limitation of how some ajax field work (e.g. TreeDropDown). Those fields need a REST endpoints to fetch data from the CMS. That REST endpoint is accessed via their parent form. However, in the case of linkfield, the parent form depends on your Link type key ... if you don't know what kind of link you are editing, ModalController can't retrive the form fields. In hindsight, AjaxField works OKish, but it's probably worth investigating some alternatives ... especially if we give ourselves permission to change things in core to accomodate it. Of the top of my head, I'm thinking we could rewrite route that fetches the link form so the link key is a URL parameter instead of a GET parameter. Alternatively, we could create versions of those form fields that call generic end points that are not tied to a form.
All this part can go if we get rid of the registry and assume that Link subclass can be managed by a LinkField. We should add an option to allow specific subclasses to be disabled in specific LinkField instances. Javascript
The file link form modal is a hack. I'm piggy backing on the File Link Form modal in the WYSIWIG. This means that you can't customised the file link form to add more information. There's probably a way to do this more cleanly if you update core. I think there could be some really nice side benefit here. For example, you could give developers the ability to use their own form schema in an Insert Media Modal. I would like to do something like that in AnyField. Frontend/backend commsI disagree that GraphQL is substantially more complex than a REST here. I think there's an argument that I'm subverting the main value GraphQL by JSON serializing the Link Form data and sending that to a GraphQL service to generate a description for it. If we're going to ditch the AnyField idea, maybe we should consider making the entire thing work with GraphQL, including the link creation/update/delete. Only the ID of the created link would be attached to the form field. That would allow us to remove a bunch of logic from the LinkField PHP because the Link creation logic would be handled by GraphQL instead. (AnyField couldn't work that way without forcing you to pre-register all your DataObject in your admin schema.) If we go REST, then I would like us to come up with a comprehensive convention of how and when we add REST endpoints to the CMS. Also, how we interact with those endpoints in React. One link solution to rule them all
I don't think this needs to be a "be-all and end-all" link management solution. People have a need to manage links outside the WYSIWYG. That's basically the problem the other link module were trying to solve. To the extent that we could combine the two to provide a seamless experience, that might be worth exploring, but I don't see it as a outright blocker.
Broken link tracking would be a plus. On the orphan link tracking, I'm tempted to put it back on the developers to define cascade delete and ownership rules. But not 100% sure about this. Overarching assumptionsThere's a couple overarching assumption that I made that probably should be made explicit.
If we are not comfortable with those assumptions, we should call it out. |
There's not a whole lot we can do to stop that from happening since people can just programatically create DataObjects, or add them via a GridField. Only way to stop it is to get has_one implementation and forced all links to be has_many which means they'll have a ParentID (page) which we could validate beforeWrite(). I don't think there is any practical need to do this though
They're not flat now, SiteTreeLink and FileLink both have relations on them to SiteTree and File respectively
That's already already doable
I'm not sure what this means. If you create a new Link type you'll automatically get a dynamic form schema created for you inside the modal. Or do you mean using the js injector to swap out the modal itself? Not sure if that's possible now, though seems unnecessary / out of scope for what we're doing here if it's not.
GraphQL is lots more cluttered/complex for no benefit - I did a quick PR to POC getting rid of graphql and you end up removing a bunch of files and get functionally the same thing. To me that's seems like classic refactoring.
Convention I had in my PR was just using
Seems like you've already implemented that in this PR. I'm happy to just merge this as is and then we can do a tidy up PR as we looks at doing other refactoring.
I'd say so since the main use case here is to put them on pages, which are versioned.
We could, though I'm not sure in what the scenario someone would be using the linkfield module and not have versioned installed
Just update the usage documentation to include $own, $cascade_deletes and $cascade_duplicates when adding Link::class to a relationship on your Page/DataObject
I've got that implemented on a PR for validation
Does "tie the permissions to an explicit owner for the link" mean just use the owner Page for the permission check? That's functionally what happens now. I've added canView() checks for objects for related data in this PR. "or to some pre-existing CMS permission" - I'm not sure what this means. We wouldn't be using the Permission::check() API here |
We discuss this at our architecture catch up yesterday. The key take away are:
|
The LinkField never went through a full peer review process.
Acceptance criteria
Related
The text was updated successfully, but these errors were encountered: