eloquent-sluggable icon indicating copy to clipboard operation
eloquent-sluggable copied to clipboard

Generate slug from the same field if explicitly modified

Open artrz opened this issue 10 months ago • 2 comments

In some cases it is useful to be able to generate the slug from the same field. Let's say I have a form where I set a title and optionally the slug. If the slug is sent it's still important to process it to make sure there are no funky chars, it is unique, etc.

This could be implemented it by adding a new config setting like honorSelf (false as default) and update SlugService::buildSlug() to generate the slug from the $attribute. Something along the next lines:

    public function buildSlug(string $attribute, array $config, bool $force = null): ?string
    {
        $slug = $this->model->getAttribute($attribute);

        if ($config['honorSelf'] && $slug && $this->model->isDirty($attribute)) {
            return $this->obtainSlug($slug, $config, $attribute);
        }

        if ($force || $this->needsSlugging($attribute, $config)) {
            $source = $this->getSlugSource($config['source']);

            if ($source || is_numeric($source)) {
                $slug = $this->obtainSlug($source, $config, $attribute);
            }
        }

        return $slug;
    }

    // ...

    protected function obtainSlug(string $source, array $config, string $attribute): string
    {
        $slug = $this->generateSlug($source, $config, $attribute);
        $slug = $this->validateSlug($slug, $config, $attribute);
        $slug = $this->makeSlugUnique($slug, $config, $attribute);

        return $slug;
    }

I'm not sure about collateral effects. If there's interest into this, I could dig deeper.

artrz avatar Apr 12 '24 18:04 artrz

I'm not sure I fully understand the use-case here.

If you have a form where you can optionally provide a slug, then you can handle funky characters, uniqueness, etc. with form validation, I would think.

cviebrock avatar Apr 16 '24 20:04 cviebrock

Yes, front side validation is always desirable even when it can be bypassed. Still, slugs should always be generated as near as possible to the persisting action for the best match at least in my case. E.g. user A fills the slug field with 'x' on his form, user B fills the slug field with 'x' and sends the form, user A sends his form. Maybe user A sends his form first but has higher network latency. Maybe an API endpoint is being used where it's not possible to rely on the 3rd party validation implementation.

Not a deal breaker, a couple of years ago I solved this by extending the trait iirc, and in my latest implementation I ended up skipping the observer reactivity by returning an empty sluggableEvent (would be cool to have a SluggableObserver::NONE) and manually calling SlugService::createSlug(). For another project I might extend SlugService and bind my custom class with the code in OP to see how it goes. Btw, in SlugService::createSlug() seems that the is_array() check is not really neaded as the agument is typehinted. Also, I'm not sure that requiring a config for the attribute should be obligatory when using this method as the source is explicitly sent.

Feel free to close.

artrz avatar Apr 17 '24 04:04 artrz