Skip to content
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

Slug Driver Support #2456

Merged
merged 22 commits into from
Dec 7, 2020
Merged

Slug Driver Support #2456

merged 22 commits into from
Dec 7, 2020

Conversation

tankerkiller125
Copy link
Contributor

@tankerkiller125 tankerkiller125 commented Nov 17, 2020

Partially Solves flarum/issue-archive#203

Changes proposed in this pull request:

  • Implements drivers for slugging for discussions and users, with the option to update slugs for other models as well.

Reviewers should focus on:

  • Are we happy with this?

Confirmed

  • Frontend changes: tested on a local Flarum installation.
  • Backend changes: tests are green (run composer test).

Required changes:

Copy link
Member

@askvortsov1 askvortsov1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO:

  • Add an extender for adding slugging drivers to models. Add integration tests for that extender
  • Can we encapsulate any of the direct querying done in the drivers into the User / Discussion Repository classes, and inject those via DI?
  • @flarum/core Confirm our stance on calling the full slug (whatever it might be) slug, and serializing it as such to the frontend. This conflicts with the current naming used by the tags extension (so that's a breaking change if we adopt it there), but it would be nice to use a common convention, and just slug seems sensible (I would also be fine with fullSlug, but Clark I know you have concerns about that, and I see where you're coming from).
  • Decide whether we want to keep the toResource URL generator; if so, adopt throughout the core codebase where possible, and add an extender / tests for it
  • Figure out what to do with frontend code that obtains discussion ID from the slug. This happens in 2 places:
    • DiscussionListItem's isActive, which can be overriden, but could also use app.current.discussion (which might make more sense).
    • DiscussionPageResolver's getDiscussionIdFromSlug helper. I don't think there's a way to universalize this one, but IMO we should move it onto the DiscussionPageResolver class so it can be overriden to generate the key in some different manner if needed by an extension.

@tankerkiller125
Copy link
Contributor Author

tankerkiller125 commented Nov 24, 2020

Regarding @askvortsov1 points above

  • Will be done shortly
  • We did not make any changes here, and likely won't
  • Keeping it slug as fullSlug no longer makes sense given that drivers will allow devs to completely replace the slugging logic
  • Keeping toResource()

@tankerkiller125
Copy link
Contributor Author

@askvortsov1 I'm going to rebase this tonight when I get home so we can fix whatever Admin stuff we need to (Admin UX got merged) and from there this PR is good to go if I'm not mistaken?

@askvortsov1
Copy link
Member

Yep! It should be good for full review then.

@tankerkiller125
Copy link
Contributor Author

Rebased this onto the master with the Admin UX changes, everything looks great and works correctly in my testing. We still need to create the translations however.

js/src/common/components/Select.js Outdated Show resolved Hide resolved
src/Discussion/IdWithSlugDriver.php Outdated Show resolved Hide resolved
src/Discussion/IdWithSlugDriver.php Outdated Show resolved Hide resolved
src/Admin/Content/AdminPayload.php Show resolved Hide resolved
src/Http/HttpServiceProvider.php Outdated Show resolved Hide resolved
src/Http/HttpServiceProvider.php Outdated Show resolved Hide resolved
src/Http/UrlGenerator.php Outdated Show resolved Hide resolved
src/User/UsernameSlugDriver.php Outdated Show resolved Hide resolved
Copy link
Member

@luceos luceos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking amazing, I am literally stunned by the implementation. Well done!

I left some considerations, questions; please have a look.

src/Api/Controller/ShowDiscussionController.php Outdated Show resolved Hide resolved
@@ -35,7 +46,7 @@ protected function getDefaultAttributes($discussion)

return [
'title' => $discussion->title,
'slug' => $discussion->slug,
'slug' => $this->slugManager->forResource(Discussion::class)->toSlug($discussion),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be easier to have a method on the abstract model instead?

$discussion->slugger->slug();

So that we resolve the slug manager late here as well, plus we can reduce the overhead on every, single class that tries to resolve the slug manager..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused how that would work tbh. I'm very wary about adding stuff to AbstractModel unless it absolutely affects ALL models, which isn't the case here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it's a trait one can apply to the model, eg Discussion has the Sluggable trait. It adds that trait, sets the property protected $slugger = DiscussionSlugger::class; and the trait handles the rest?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this. It adds unnecessary static stuff to the models, and I'd really prefer to move away from that as much as we possibly can because it's unnecessary leakage of global state. It also makes the extension mechanism a lot more hacky (similar to what I had to do with #2460), which I really didn't like and will revisit again after stable.

src/Forum/Content/Discussion.php Show resolved Hide resolved
Copy link
Member

@SychO9 SychO9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! nice work!

I believe it'd be better to have IdOnlyUserSlugDriver here instead of the nicknames extension.

If I make for example another extension that adds a different user display name driver, the admin might want to use this IdOnlyUserSlugDriver but then I'd have to also add it to my own extension, because it only resides within the nickname extension.

Let me know what you think.

this.slugDriverOptions[model] = {};

app.data.slugDrivers[model].forEach((option) => {
this.slugDriverOptions[model][option] = option;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the keys getting localized somewhere ? I mean default and idOnly for example (same with display name drivers) They don't seem to be, at least the option's label not the key itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, and mail drivers aren't either. That's a limitation worth revisiting later IMO

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now, something like app.translator.trans('core.admin.basics.slug_drivers.${option}') wouldn't work, since extensions are adding drivers, and that means they couldn't add locales for the drivers anyway.

The solution would need to be more sophisticated. Yeah worth revisiting it later.

src/Http/HttpServiceProvider.php Outdated Show resolved Hide resolved
Copy link
Member

@askvortsov1 askvortsov1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it'd be better to have IdOnlyUserSlugDriver here instead of the nicknames extension.

On second thought, I agree with this, and that goes for IdOnlyDiscussionSlugDriver as well (and that doesn't break anything with the frontend stuff since the ID is still first).

Copy link
Member

@SychO9 SychO9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have nothing else to add, it all looks good to me.

Just noting that we need of course to remember to add the id only drivers in core and to add the nicknames extension to composer.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants