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

Uuid Extra Bundle Laravel Package

mcfedr/uuid-extra-bundle

A Symfony bundle that adds UUID support to your application, including Doctrine types, form types, validators, and generators so you can use UUIDs as primary keys and identifiers with less configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install it alongside Ramsey UUID — the bundle is a thin adapter, not a replacement:

    composer require ramsey/uuid mcfedr/uuid-extra-bundle
    

    4.2.0 is a platform-support release, not a feature release. Its only stated change is "Drops support for older PHP and Symfony," so before composer require succeeds you need to know what "older" means for your app: open the bundle's composer.json and read the php and symfony/* constraints, then compare with your own. On a current LTS this is usually a non-event; on PHP 7.4 or Symfony 5.3 the install will refuse. Also re-check the ramsey/uuid constraint — 3.x used a concrete Uuid class, 4.x uses UuidInterface + Uuid::fromString(), and the bundle is written against exactly one of those two APIs. If the constraint pins you to an old Ramsey, the type-hints in the converter and normalizer won't line up with your code.

  2. Register the bundle if Flex doesn't do it for you:

    // config/bundles.php
    return [
        // ...
        Mcfedr\UuidExtraBundle\McfedrUuidExtraBundle::class => ['all' => true],
    ];
    
  3. Confirm what actually got wired up — this is the fastest way to learn the package, because there are only three moving parts:

    bin/console debug:container | grep -i uuid
    bin/console debug:container --tag=serializer.normalizer | grep -i uuid
    bin/console debug:container --tag=request.param_converter
    

    Then read vendor/mcfedr/uuid-extra-bundle/src/. The whole surface is a handful of classes (UuidParamConverter, UuidNormalizer, UuidType); the supports() method in the converter tells you exactly which type-hints it acts on. Do this again after 4.2.0 — a release that drops old Symfony may also have dropped the Sensio dependency, so the converter you're expecting might no longer be there.

  4. First use case — stop parsing UUIDs in every controller. Put the interface type-hint in the action and let the converter do the work:

    #[Route('/orders/{orderId}', methods: ['GET'])]
    public function show(UuidInterface $orderId): Response
    {
        // $orderId is already a UuidInterface, or a 404 was thrown
    }
    

    The second-most-common first use is the form type:

    $builder->add('id', UuidType::class);
    

    and the third is the serializer normalizer, which makes an entity property typed UuidInterface round-trip as a plain JSON string instead of an object graph.

Implementation Patterns

Entity IDs. The bundle does not persist anything. Use ramsey/uuid-doctrine for the Doctrine type, and construct the ID in the entity:

use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;

class Order
{
    private UuidInterface $id;

    public function __construct()
    {
        $this->id = Uuid::uuid4();
    }

    public function getId(): UuidInterface { return $this->id; }
}

Keep the DBAL type (uuid or uuid_binary) and the PHP type consistent — the converter and normalizer only understand the PHP side.

Controller / route conversion. With sensio/framework-extra-bundle installed and auto_convert enabled (the default), any action argument typed UuidInterface whose name matches a route placeholder is converted automatically. Argument name must match the placeholder, so either name the placeholder {orderId} and the argument $orderId, or add an explicit #[ParamConverter]. Treat the conversion as "parse or 404" — it is not validation. If you need a 400 on malformed input for PUT/PATCH/DELETE, parse inside the action (Uuid::fromString() in a try/catch) rather than relying on the converter.

Serializer round-trip. Once the normalizer is registered, UuidInterface properties serialize to canonical strings and deserialize from strings:

$json  = $serializer->serialize($order, 'json');          // {"id":"9f1c...","...":...}
$order = $serializer->deserialize($json, Order::class, 'json'); // back to UuidInterface

This is what makes DTOs with UUID properties work with #[MapRequestPayload] / #[MapQueryString] in Symfony 6.3+: the deserializer handles the conversion, and failures surface as NotNormalizableValueException, which the framework turns into a 400.

Forms. UuidType handles both directions, so the same field works for create and edit:

$builder->add('id', UuidType::class, [
    'required'        => false,
    'invalid_message' => 'That is not a valid UUID.',
]);

Make the backing property nullable if you set required => false, otherwise an empty submission will blow up on assignment.

Custom value resolver for modern Symfony. If you're on 6.2+ and have dropped Sensio, the converter won't fire — and if 4.2.0 dropped the converter as part of the Symfony floor bump, this is now the required integration point rather than an optional one. Verify with debug:container --tag=request.param_converter; if nothing UUID-shaped is listed, wire your own:

final class UuidValueResolver implements ValueResolverInterface
{
    public function resolve(Request $request, ArgumentMetadata $argument): iterable
    {
        if ($argument->getType() !== UuidInterface::class) {
            return [];
        }
        $value = $request->attributes->get($argument->getName());
        if (!is_string($value) || !Uuid::isValid($value)) {
            throw new NotFoundHttpException();
        }
        return [Uuid::fromString($value)];
    }
}

Register it with kernel.controller_arguments priority and you've replaced the bundle's param converter with something you control.

Gotchas and Tips

  • The 4.2.0 minor bump hides a breaking change. SemVer-wise it's a patch/minor, but "drops support for older PHP and Symfony" means an upgrade can fail on a stack that installed 4.1.x fine. Pin your constraint ("mcfedr/uuid-extra-bundle": "^4.1" vs "^4.2") deliberately, and don't let a composer update silently move you onto a bundle your runtime can't satisfy. Check the CI matrix before trusting it.

  • The param converter is still the fragile part. Even after the Symfony floor bump, sensio/framework-extra-bundle is abandoned and absent from Symfony 7. If 4.2.0 still requires it, the bundle inherits that expiry date. Read the require block — if the converter is the only reason you want it, a 20-line value resolver is a better long-term bet.

  • UuidInterface vs Uuid matters. Version 3.x of ramsey/uuid used a concrete Uuid class; 4.x uses UuidInterface. If the converter's supports() checks for the wrong one, UuidInterface type-hints silently fall through to a "could not convert" error. Read supports() before debugging anything else.

  • 404 vs 400 semantics. A malformed UUID in a route currently looks identical to "row not found." That's acceptable for GET, but don't let it leak into write endpoints — clients can't tell a typo from a missing record.

  • Non-canonical input is accepted. Uuid::fromString() takes uppercase and dash-less forms. If your API promises canonical lowercase output, normalise on write ($uuid->toString()) and compare, or reject inputs where strtolower($input) !== $uuid->toString().

  • Watch for silent normalizer conflicts. API Platform ships its own UUID normalizers with high priority, so the bundle's normalizer may never run. The symptom of no normalizer at all is a UuidInterface serialized as an object graph ({"bytes":...} or nested fields) — check debug:container --tag=serializer.normalizer and adjust priority. Re-check after 4.2.0, since a Symfony floor bump can reorder the default normalizer chain.

  • Binary UUIDs need care. With uuid_binary DBAL types the value in PHP is a UuidInterface but the column is binary(16). Don't hand a binary string to UuidType as a form value; let the entity transformer do it.

  • Debug the converter path, not the UUID. If conversion "isn't running," it's nearly always auto_convert off, the argument name not matching the placeholder, or a missing request.param_converter tag — not the UUID parsing itself. debug:event-dispatcher kernel.controller plus a breakpoint in supports() settles it in a minute.

  • Tests worth writing. One WebTestCase hitting /orders/not-a-uuid to pin down your 404-vs-400 policy, and one serializer round-trip test asserting the JSON shape of a UUID property. Both catch regressions on every Symfony, Ramsey, or bundle bump — including the 4.2.0 platform change.

  • Maintenance signal changed, but only slightly. The "last release 2022" abandonment warning no longer applies — 4.2.0 shows someone is still cutting releases. But the cadence is slow and the package is tiny (still low stars, zero dependents), so don't expect same-day support for whatever Symfony ships next. The fork advice still holds: if a future constraint or a supports() check blocks your upgrade, copying the handful of classes into src/ and owning them is cheaper than waiting on a release.

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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle