pierstoval/character-manager
Character Manager is a PHP package for organizing character data in your projects. It offers a simple structure for defining, storing, and retrieving characters, making it useful for Laravel/PHP apps that need lightweight character management.
Reality check first: this is a Symfony bundle using Doctrine ORM, not a Laravel package. There is no service provider, no Eloquent, no config/character-manager.php. If you're on Laravel, treat this as a reference implementation you copy patterns from, not something you composer require. If you're on Symfony, it installs but is effectively unmaintained (v2.1.0 is the only release in years, ~8 stars, zero dependents) — pin it and expect to own the code.
What v2.1.0 changes for you: Symfony 4 support is gone (baseline is now Symfony 5.x), PHP minimum is 7.4 (up from 7.2), the doctrine/inflector dependency was dropped, and all project classes moved from the repo root into src/. None of this modernizes the package — it still does not target Symfony 6/7 or PHP 8.3+.
Minimal Symfony setup:
composer require pierstoval/character-manager and register Pierstoval\Bundle\CharacterManagerBundle\CharacterManagerBundle in config/bundles.php.src/DependencyInjection/Configuration.php before writing any app code (note the src/ prefix — this path changed in v2.1.0, so stale blog posts and older copies of the README point at the repo root). The whole package is config-driven: it asks you to point at your own entity classes (character, character type, and likely the join/assignment entity). There is no usable default; the bundle is a skeleton waiting to be filled in with your classes.src/Model/, src/Interfaces/, and src/Doctrine/ in vendor/pierstoval/character-manager/. The bundle ships traits + interfaces (e.g. a character trait, a character-type trait) that you apply to your own Doctrine entities so the bundle's manager service can operate on them. Read the interfaces — they define the entire contract.bin/console debug:config character_manager (or whatever the extension alias resolves to) to see what keys the bundle actually accepts, since the README is a skeleton too.CharacterType (name, label, maybe stat template) and Character (name, owning user, type reference) — and let the bundle wire them through its manager service rather than writing CRUD by hand.If you only have an hour: skim the interfaces, copy the traits into your entity, run one migration, and save/retrieve a character through the manager. That tells you whether the package does more than a make:entity would.
Extend, don't patch. The intended pattern is class-replacement via config: you write your own App\Entity\Character implementing the bundle's character interface and using its trait, then tell the bundle in YAML/config that this is "the" character class. Same for the type entity. This is the FOSUserBundle/sonata-style approach — the bundle orchestrates, you own the schema. The v2.1.0 src/ move doesn't change any of this; it only changes where you read the reference code.
Manager service as the single write path. Resolve the bundle's manager from the container (constructor injection) and route all character creation/assignment through it instead of calling $entityManager->persist() yourself. If there's a save/create method on the manager, it likely handles the type lookup and the owning-user association that you'd otherwise forget, and it gives you one seam to add validation, limits ("max 3 characters per account"), or event dispatch.
Lean on the new deterministic ordering. v2.1.0 "properly sorts managers configs and steps by keys" — you can now assume managers and steps execute in key order rather than YAML declaration order. Use this deliberately: name keys so the natural alphabetical order matches your intended pipeline (assign_user before roll_stats before persist), and write integration tests against named steps instead of asserting on array position.
Character type as a catalog, not an enum. Treat the type entity as seedable data you load via fixtures (CharacterTypeFixtures) and reference by slug/code from the UI, not as a hardcoded PHP enum. Games grow classes; changing data beats changing code and redeploying. It also lets the bundle's type trait carry per-type metadata (stat templates, portraits) without schema changes.
Wrap the bundle in your own domain service. Given the maintenance risk, put an App\Character\CharacterFactory (or similar) between your controllers and the bundle's manager. One day you may need to swap the bundle out; if your controllers only ever call your own service, the migration is a single class. This is the highest-leverage pattern in the whole assessment.
Symfony integration tips: implement the bundle's interfaces on entities that extend User/Character, use Doctrine mappedSuperclass if you need multiple character tables, add a Voter/AccessControl on the character's owner for authorization, and expose characters over API Platform or a serializer group if you're building the game client separately. Load the manager lazily if it's heavy.
For Laravel readers: map the concepts one-to-one. Character type → CharacterType model seeded by a seeder. The bundle's manager service → a CharacterService class bound in a service provider. The trait → a HasCharacter concern. The interfaces → PHP contracts you define. You will reproduce this in ~2 hours of work, and it will be maintained.
src/ move breaks copy-pasted paths. Anything you bookmarked — Model/, Interfaces/, DependencyInjection/Configuration.php — is now under src/. If a config reference, an autoload path, or an @PierstovalCharacterManager/... template path stops resolving after the bump, check whether it was written against the pre-2.1.0 layout.vendor/ — read Configuration.php, the extension class, and the interfaces. Do not trust blog posts or guess config keys; a wrong key in a bundle's config.yml can silently no-op.composer require will still fail. Use --ignore-platform-reqs only to inspect the code, not in production. Realistically you either pin to a Symfony 5 stack (increasingly untenable) or fork the bundle into your src/ namespace (fine, and probably the right call). Check .github/workflows/ — since CI moved to GitHub Actions in this release, the workflow matrix is now your only honest source of what PHP/Symfony combinations are actually exercised.doctrine/inflector is no longer pulled in for you. If your own code happened to rely on it transitively through this bundle, add it explicitly to your composer.json before upgrading or you'll get class-not-found at runtime.#[ORM\AttributeOverride] / @AttributeOverride for trait-provided columns, and always run doctrine:schema:validate after applying a trait — mapping errors here surface at runtime, not boot.App\Entity\Character that doesn't yet implement the required interface produces container errors at cache-warm, not on install. Clear the cache (bin/console cache:clear) after editing entity classes; Symfony caches the compiled container aggressively.\RuntimeExceptions that hide the real constraint.CharacterStat entity joined to the character — don't expect the skeleton to expand.composer.lock, add a composer why-not check to CI, and consider composer patch or a vcs repository entry so you control updates. v2.1.0 was a one-off housekeeping release, not a sign of renewed maintenance — with zero dependents upstream, you are the maintainer of your fork in practice.How can I help you explore Laravel packages today?