protected function generateSlug(string $source, array $config, string $attribute): string
    {
        $separator = $config['separator'];
        $method = $config['method'];
        $maxLength = $config['maxLength'];
        $maxLengthKeepWords = $config['maxLengthKeepWords'];

        if ($method === null) {
            $slugEngine = $this->getSlugEngine($attribute);
            $slug = $slugEngine->slugify($source, $separator);
        } elseif (is_callable($method)) {
            $slug = call_user_func($method, $source, $separator);
        } else {
            throw new \UnexpectedValueException('Sluggable "method" for ' . get_class($this->model) . ':' . $attribute . ' is not callable nor null.');
        }

        $len = mb_strlen($slug);
        if (is_string($slug) && $maxLength && $len > $maxLength) {
            $reverseOffset = $maxLength - $len;
            $lastSeparatorPos = mb_strrpos($slug, $separator, $reverseOffset);
            if ($maxLengthKeepWords && $lastSeparatorPos !== false) {
                $slug = mb_substr($slug, 0, $lastSeparatorPos);
            } else {
                $slug = trim(mb_substr($slug, 0, $maxLength), $separator);
            }
        }

        return $slug;
    }