Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Levenify Bundle Laravel Package

levenify/levenify-bundle

Levenify Bundle integrates Levenify's fuzzy string matching into Symfony apps, making it easy to add Levenshtein-based similarity checks, typo-tolerant search, and record deduplication. Configure thresholds and services, then compare strings quickly in PHP.

View on GitHub
Deep Wiki
Context7

Getting Started

Three steps, in order.

1. Inspect before you install. The package name says "bundle" and the description says "Symfony 5." There is no Laravel service provider and no extra.laravel block, so Composer will install it but Laravel will not discover anything. Before running composer require, do a dry run to see what constraints you're pulling in:

composer require levenify/levenify-bundle --dry-run

If the symfony/* constraints don't align with your Laravel version's Symfony components (Laravel 10/11 ships Symfony 6/7), stop here and go to the vendoring path in Implementation Patterns. Do not force it with --ignore-platform-reqs on a production app.

2. Read the actual algorithm. The public API is one class, not the bundle. Look at:

vendor/levenify/levenify-bundle/src/

Find the class exposing the distance/compare method — likely Levenify, Levenshtein, or similar. Confirm three things before writing any code:

  • Is the class free of constructor dependencies?
  • Does it take plain strings, or does it wrap Symfony HTTP/Request objects?
  • Does it reference any Symfony\* types in the method signatures?

If the answer to the last question is "yes," you cannot use it directly in a Laravel controller without pulling that Symfony component in — which means the realistic path is vendoring.

3. First use case: typo-tolerant input matching. Not search infrastructure, not indexing — a single pair comparison behind a threshold. That is the smallest thing that tells you whether the algorithm actually beats PHP's native levenshtein() on your data.

// Once the class is confirmed usable, either resolve it or instantiate directly:
$lev = app(\Levenify\Levenify::class); // after binding it (see below)
// or, if the FQCN is different, use the real one from vendor/
$distance = $lev->distance('kitten', 'sitting');

Compare that output against levenshtein('kitten', 'sitting') on ten pairs of your real data — company names, SKUs, addresses — before you build anything on top of it. If the results match and your inputs are short ASCII strings, stop: use PHP's native function and close the ticket. The bundle only earns its place when the native function fails you (multibyte input, strings over 255 characters, or you need a normalized 0–1 score).

Implementation Patterns

Bind it once, inject everywhere. If the class has no constructor dependencies, register it as a singleton in AppServiceProvider::register():

$this->app->singleton(\Levenify\Levenify::class, function () {
    return new \Levenify\Levenify();
});

Then type-hint the class in the constructor of whatever needs it. Never new it at the call site — that's the difference between a swappable dependency and a hardcoded one, and you will want to swap it after the benchmark in Getting Started.

Wrap it behind an application-owned interface. This is the single most important pattern for this package, because the upstream is a 3-star, single-maintainer Symfony 5 bundle you may not be able to upgrade. Define your own contract:

interface StringSimilarity
{
    public function distance(string $a, string $b): int;
    public function ratio(string $a, string $b): float; // 0.0–1.0
}

Bind LevenifySimilarity implements StringSimilarity as the default, with a NativeLevenshteinSimilarity fallback. Call sites depend only on StringSimilarity. Now the package is replaceable in one binding without touching a single consumer.

Vendor the algorithm, don't depend on the bundle. Given the Symfony 5 packaging and the dependency risk, the strongest day-to-day pattern is to copy the MIT-licensed routine into app/Support/StringSimilarity/ with the license header and attribution retained. You get:

  • No Composer constraint conflicts with your Symfony components.
  • No abandoned-maintainer risk.
  • Full control over Unicode and length handling.

This requires you to have read and understood the routine (do that in Getting Started step 2), and to write tests for it (below).

Normalize before you compare. Never pass raw user input to the distance function. Create a normalizer and chain it:

class Normalizer
{
    public function normalize(string $s): string
    {
        $s = mb_strtolower($s, 'UTF-8');
        $s = trim(preg_replace('/\s+/', ' ', $s));
        // transliterate accents if your data mixes "café" and "cafe"
        return $s;
    }
}

The distance is only as good as the normalization in front of it. This is where most day-to-day bugs come from — not the algorithm.

Threshold on ratio, not raw distance. Raw edit distance is length-dependent: a distance of 3 is disastrous for "abc" but trivial for a 60-character address field. Convert to a normalized ratio and threshold on that:

$ratio = 1 - ($distance / max(mb_strlen($a), mb_strlen($b)));
$isMatch = $ratio >= 0.85; // tune against labeled pairs

Prefilter before you compare. Levenshtein is O(m×n) per pair. Fuzzy matching an incoming string against 10,000 candidates is 10,000 comparisons — do not do this in a request path. Cheap prefilters that cut the candidate set first:

  • Require the first character to match.
  • Require abs(strlen($a) - strlen($b)) <= maxDistance (length difference bounds edit distance).
  • Use a LIKE 'prefix%' or a pg_trgm index to narrow before applying the expensive comparison.

Batch and cache for import/dedupe flows. For CSV imports, build a signature (e.g., soundex or first-N-chars) and only compare within signature buckets. Cache repeated pair results — in a dedupe job, the same pairs often recur across passes.

Feature-flag the integration. Put the similarity service behind a config flag (similarity.driver = native | levenify) so you can A/B the two on real traffic and roll back instantly if latency or accuracy regresses.

Gotchas and Tips

It will not auto-register in Laravel. There is no LevenifyServiceProvider and no extra.laravel in composer.json. composer require succeeds, but nothing is bound. You must bind it yourself (see Implementation Patterns) or you'll get "Target class does not exist" errors that look like an install failure but aren't.

The "better" claim is unverified. The description says "a better Levenshtein function" but there is no published benchmark in the repo against PHP's native C-implemented levenshtein(). A pure-PHP implementation with better Unicode handling is very likely slower than the native function on short ASCII strings. Verify before you assume the bundle is a strict upgrade. If your strings are all under 255 chars and ASCII, the native function is genuinely hard to beat.

Unicode is the make-or-break case. The whole reason to reach for this package is multibyte input — accents, emoji, CJK, combining characters. Test it explicitly:

// These should all behave sanely:
$this->assertEquals(0, $sim->distance('café', 'café'));
$this->assertGreaterThan(0, $sim->distance('café', 'cafe'));
$this->assertEquals(0, $sim->distance('👍', '👍'));

If mbstring is not enabled in your PHP environment, the results will be wrong silently. Check php -m | grep mbstring in every environment, including CI.

Length limits matter. Native levenshtein() in PHP returns -1 and emits a warning for strings over 255 characters. A pure-PHP implementation may have no such limit, or may have a different one, or may blow memory on very long inputs. Cap input length in your wrapper (e.g., mb_substr($s, 0, 1000)) and document the cap.

Composer constraint conflicts are likely. A Symfony 5 bundle pins symfony/* at ^5.0, while current Laravel ships Symfony 6/7 components. composer require may fail or, worse, downgrade Symfony components and break other Laravel internals. Always use composer why-not levenify/levenify-bundle and composer require --dry-run before committing to an install.

Symfony 5 is end-of-life. Even if you can install it, the framework it targets receives no security patches. A bundle pinned to EOL Symfony will not track your PHP or Laravel upgrades. This is the strongest argument for vendoring.

The bundle glue is not the value. LevenifyBundle::class and the container extension exist to register the algorithm service in a Symfony container. In Laravel you have no use for either. Do not try to bridge the Symfony DI container into Laravel — you'll spend more time on glue than the algorithm is worth. Extract the function.

Testing is on you. With one maintainer and no test signals in the repo description, treat the algorithm as untested in your context. Write your own suite: known distance pairs (kitten/sitting = 3), empty strings, identical strings, Unicode, long strings, and the boundary of your length cap. These tests are the guardrail that lets you vendor confidently.

Keep the MIT notice. If you copy the routine into app/Support/, retain the copyright and LICENSE file content in a header comment. This is trivial and legally required — do not skip it under time pressure.

Exit plan is the whole point. Budget for the package to be abandoned. The StringSimilarity interface and a one-line binding are what let you walk away in a single PR — either to native PHP, to a vendored copy, or to a maintained library. Design for the swap from day one and the rest of the risk is manageable.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource