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

User Bundle Laravel Package

plume-solution/user-bundle

User bundle for Plume Solution applications, offering ready-made user account and authentication foundations. It helps you add registration, login, profiles, and role-based access with less boilerplate, while keeping user handling configurable and easy to integrate.

View on GitHub
Deep Wiki
Context7

Getting Started

Step zero: confirm the framework before you install anything. Despite the Laravel framing in the description, this artifact is named user-bundle and its own metadata says "a new bundle." Bundle is Symfony's packaging and registration unit — config/bundles.php plus a DependencyInjection/*Extension class. Laravel has no loader for that; Composer will happily drop the files in vendor/ and nothing will register routes, config, migrations, or a User model. Run this audit before writing code:

composer show plume-solution/user-bundle --all   # versions, requires, last release
# or against the clone:
grep -E '"(php|symfony/|doctrine/|laravel/|illuminate/)' composer.json
ls src/ | head -50                               # look for *Bundle.php, DependencyInjection/
ls src/Resources/config/ 2>/dev/null             # services.yaml, routing.xml, doctrine mappings

If you see *Bundle.php, DependencyInjection/, Resources/ — you're in Symfony. If you see src/UserServiceProvider.php, src/Models/, database/migrations/ — it's Laravel-shaped after all, and the audit continues normally. Almost certainly it's the former.

If your app is Laravel (the stated audience): the honest day-to-day answer is that you cannot leverage this package — you leverage its feature list. Spend an hour turning its capability claims into a checklist and mapping each to first-party tooling:

Bundle claim Laravel equivalent
User model + migrations php artisan make:model User -m (already in a fresh app)
Registration / login / reset composer require laravel/fortify (headless) or laravel/breeze (scaffolded)
CRUD for accounts Fortify's ProfileInformation action, or a resource controller
Role & permission hooks spatie/laravel-permission or Gate/Policy
Email verification MustVerifyEmail on the model
Config-driven config/fortify.php

Then delete the vendor directory. That mapping is the deliverable.

If you're genuinely on Symfony and still want the spike (internal tool, hard time-box, throwaway branch):

  1. Pin to a commit — with zero releases you want reproducibility:
    composer require plume-solution/user-bundle:dev-main#<sha>
    
  2. Register it manually unless Flex prompted for a recipe:
    // config/bundles.php
    PlumeSolution\UserBundle\PlumeUserBundle::class => ['all' => true],
    
  3. Discover the config root — the README is a stub, so let the console be your documentation:
    php bin/console config:dump-reference | grep -i plume
    php bin/console debug:config <vendor>_user
    
  4. Check the data model. If the bundle ships a Doctrine entity, point it at your class via resolve_target_entities; if it expects you to provide one, you're implementing Symfony\Component\Security\Core\User\UserInterface and the bundle is only supplying controllers/templates.
  5. Wire security.yaml and run php bin/console debug:firewall main plus doctrine:schema:validate before touching a browser.

First use case, scoped tightly: get GET /register → POST /register → POST /login → authenticated dashboard rendering for one seeded user, in a branch, in one day. If any of those four steps fights you for more than a few hours, that's your verdict: fork-and-own is now a real sprint, and the framework's MakerBundle-generated User + make:auth is cheaper.

Implementation Patterns

1. Facade the bundle behind your own interface — non-negotiable. Everything you write should depend on an app-owned contract, so ripping the bundle out is a search-and-replace rather than an archaeology project:

namespace App\Identity;

interface UserManagerInterface
{
    public function register(string $email, string $plainPassword): UserInterface;
    public function changePassword(UserInterface $user, string $newPassword): void;
}

Implement it by decorating the bundle's service (App\Identity\BundleUserManager wrapping the vendor service) and bind the interface in config/services.yaml. If you fork, you rewrite one class instead of every controller.

2. Use resolve_target_entities instead of editing vendor mapping. This is the standard Symfony pattern for bundles that ship a mapped entity:

# config/packages/doctrine.yaml
doctrine:
    orm:
        resolve_target_entities:
            PlumeSolution\UserBundle\Model\UserInterface: App\Entity\User

Then App\Entity\User extends PlumeSolution\UserBundle\Model\User (or the mapped superclass) and add your own columns. Extending a concrete entity forces you into JOINED/SINGLE_TABLE inheritance — check which one the bundle's mapping already declares before you commit to a strategy.

3. Firewall and provider wiring is where the day goes. A workable baseline you'll adapt:

# config/packages/security.yaml
security:
    password_hashers:
        App\Entity\User:
            algorithm: auto
            migrate_from: [bcrypt]

    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: email

    firewalls:
        main:
            lazy: true
            provider: app_user_provider
            form_login:
                login_path: app_login
                check_path: app_login
                enable_csrf: true
            login_throttling: { max_attempts: 5 }
            logout:
                path: app_logout
                invalidate_session: true

Confirm which property the bundle's own provider assumption uses — username vs email mismatches produce "no user found" errors that look like bad credentials.

4. Import the bundle's routes under your prefix, and override templates the Symfony way. Don't copy controllers:

# config/routes/plume_user.yaml
plume_user:
    resource: '@PlumeUserBundle/Resources/config/routing.xml'
    prefix: /account

Override views by path convention — templates/bundles/PlumeUserBundle/Registration/register.html.twig — and override a single controller action via the controller: key on the import if the flow is close but not right.

5. Hook behavior with events and decoration, not by editing vendor code. Registration flows typically dispatch something like UserRegisteredEvent. Subscribe, send your welcome mail, provision a tenant, and keep the bundle unaware:

#[AsEventListener(event: UserRegisteredEvent::class)]
final class SendWelcomeEmail { /* … */ }

Verify the event name first with php bin/console debug:event-dispatcher | grep -i user.

6. Treat roles as coarse and build authorization yourself. role_hierarchy in security.yaml is fine for ROLE_ADMIN ⊃ ROLE_USER. For anything resource-scoped ("can edit this post"), write a Voter. The bundle's "role hooks" are almost certainly just a roles column plus getRoles() — plan for IS_AUTHENTICATED_* attributes and voters on top.

7. Test the flow as a functional test, not a unit test. What you actually need to know is whether the firewall, hasher, and provider agree:

public function testRegistrationThenLogin(): void
{
    $client = static::createClient();
    $client->request('POST', '/account/register', [
        'registration_form' => ['email' => '[email protected]', 'plainPassword' => ['first' => 'S3cret!x', 'second' => 'S3cret!x']],
        '_token' => /* pull from DOM or disable CSRF in test config */,
    ]);
    $client->followRedirect();
    $this->assertSelectorExists('[data-test="dashboard"]');
}

Seed fixtures with UserPasswordHasherInterface, never with a plaintext setPassword().

8. When you fork (likely outcome), fork at the interface boundary. Copy src/ into app/Identity/, keep the same namespace mapping via Composer autoload.psr-4, replace the vendor requirement with a path repository, and preserve the test suite if there is one. Tag 0.1.0-internal so Composer constraints stay meaningful, and write down the upstream commit you forked from — you'll want it when a CVE hits symfony/security-core.

Gotchas and Tips

The naming is the biggest bug. "Bundle" means Symfony. Any Laravel-facing plan built on this package is built on a misread; the package cannot register a service provider that doesn't exist. Verify once, then stop debating it.

No Flex recipe → no automatic config file. Flex normally writes config/packages/plume_user.yaml for you. Without a recipe you get nothing, and config:dump-reference only works if the extension defines a Configuration class — many scaffold-stage bundles don't. Fall back to reading DependencyInjection/Configuration.php directly; it is the real documentation.

Interface churn will bite you on modern Symfony. Bundles from the 4.x/early-5.x era implement UserInterface::getUsername() and take PasswordEncoderInterface. Since 5.3 you need getUserIdentifier(), and 6.0 removed getUsername(), getSalt(), and the encoders. If the source shows those, you are running a compatibility patch exercise before you run a feature. composer why-not symfony/security-bundle tells you fast.

Grep for the hashing primitive before anything else.

grep -rnE 'md5|sha1|hash\(|password_hash|crypt\(' src/

A user-management package that hashes manually instead of delegating to the framework's hasher is an immediate stop. Also check eraseCredentials() exists and blanks the plaintext.

The "hooks" for roles are usually just a roles JSON column. Symfony's getRoles() must always return ROLE_USER at minimum or authorization silently degrades. Assert it in a test.

Registration forms need CSRF by default. Symfony's form component enables it; if the bundle hand-rolls a form, verify a token is present. Absence isn't a theoretical risk — it's a concrete CSRF on account creation.

Session handling after password change is a classic gap. Changing a password should invalidate other sessions. Look for SessionRegistry/Security::logout() usage or plan to add invalidate_session handling yourself.

Email verification and password reset tokens are the two flows most likely to be stubs. A reset token without a TTL, without single-use invalidation, or stored unhashed is a finding. Check the column type and the lookup query.

Debugging toolkit, in the order you'll reach for it:

php bin/console debug:router | grep -i user
php bin/console debug:firewall main          # is the listener even attached?
php bin/console debug:container | grep -i plume
php bin/console debug:event-dispatcher | grep -i user
php bin/console doctrine:schema:validate     # mapping drift after your subclass

In the browser, the Symfony profiler's Security panel answers "which provider, which token, which voter denied me" faster than any log.

Pin the commit, and budget for a re-audit. With no tags and no release history, dev-main is a moving target. Pin the SHA in composer.json, and add a calendar reminder to re-diff upstream quarterly — you own whatever lands.

Keep it off the critical path. No transitive dependency on the bundle, no bundle types in your public API, no bundle events in your domain model. The escape hatch costs you one class today and one rewrite later if you skip it.

The most valuable use of this package is the checklist it implies. Registration, login/logout, reset, verification, profile editing, roles, admin CRUD, deactivation/deletion, session management. Walk that list against your Fortify/Breeze/SecurityBundle setup and mark what's missing. That exercise produces more value per hour than any integration attempt — and you can do it in an afternoon with the vendor directory already deleted.

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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
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
adachsoft/api-version-bundle
cgv/localized-resource